// tweaks-app.jsx
// Cafe mock — Tweaks state + controls. Mounts a floating Tweaks panel
// and writes every value to CSS custom properties on :root so the
// stylesheet (in <style> in index.html) reflects changes live.

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "classic",
  "bg": "#F5EFE6",
  "text": "#1F1B16",
  "heading": "#2A211A",
  "accent": "#7A5A3A",
  "rule": "#D9CDB8",
  "footerBg": "#1F1B16",
  "fontPair": "serifSans",
  "baseSize": 16,
  "headingWeight": 500,
  "headingTracking": -2,
  "logoTracking": 32,
  "contentWidth": 1080,
  "sectionPad": 6,
  "radius": 6,
  "heroHeight": 560,
  "heroMono": 0,
  "heroDarken": 38,
  "heroAlign": "center",
  "kicker": "Coffee, slowly",
  "heroTitle": "ゆっくり、coffee と。",
  "heroSub": "ハンドドリップで一杯ずつ。日々の合間に立ち寄れる、ふつうのカフェ。",
  "menuRule": "dotted",
  "menuRowHeight": 1.9,
  "cardOpacity": 100
}/*EDITMODE-END*/;

const PALETTES = {
  classic: { bg: "#F5EFE6", text: "#1F1B16", heading: "#2A211A", accent: "#7A5A3A", rule: "#D9CDB8", footerBg: "#1F1B16" },
  cream:   { bg: "#FBF6EC", text: "#2B2419", heading: "#3D2E1E", accent: "#B58A53", rule: "#E8DCC4", footerBg: "#2B2419" },
  mist:    { bg: "#EEF0EE", text: "#23262A", heading: "#1A2A2E", accent: "#4F6B6E", rule: "#CFD6D2", footerBg: "#1A2A2E" },
  moss:    { bg: "#EFEEE3", text: "#23261C", heading: "#2C3422", accent: "#5A6B3A", rule: "#CFD0B6", footerBg: "#2C3422" },
  dark:    { bg: "#161310", text: "#E8E1D2", heading: "#F2EAD6", accent: "#C8A66B", rule: "#3A322A", footerBg: "#0E0B08" },
};

const FONT_PAIRS = {
  serifSans: { display: "'Fraunces', Georgia, serif",        body: "'Inter', system-ui, sans-serif" },
  serif:     { display: "'Fraunces', Georgia, serif",        body: "'Fraunces', Georgia, serif" },
  sans:      { display: "'Inter', system-ui, sans-serif",    body: "'Inter', system-ui, sans-serif" },
  mincho:    { display: "'Shippori Mincho', 'Fraunces', serif", body: "'Shippori Mincho', 'Fraunces', serif" },
};

function applyTweaks(t) {
  const root = document.documentElement;
  const set = (k, v) => root.style.setProperty(k, v);

  // colors — palette acts as a base, individual pickers override
  const p = PALETTES[t.palette] || PALETTES.classic;
  set("--bg", t.bg || p.bg);
  set("--text", t.text || p.text);
  set("--heading", t.heading || p.heading);
  set("--accent", t.accent || p.accent);
  set("--rule", t.rule || p.rule);
  set("--footer-bg", t.footerBg || p.footerBg);

  // typography
  const pair = FONT_PAIRS[t.fontPair] || FONT_PAIRS.serifSans;
  set("--font-display", pair.display);
  set("--font-body", pair.body);
  set("--base-size", `${t.baseSize}px`);
  set("--heading-weight", String(t.headingWeight));
  set("--heading-tracking", `${t.headingTracking / 100}em`);
  set("--logo-tracking", `${t.logoTracking / 100}em`);

  // layout
  set("--content-width", `${t.contentWidth}px`);
  set("--section-pad", `${t.sectionPad}rem`);
  set("--radius", `${t.radius}px`);

  // hero
  set("--hero-height", `${t.heroHeight}px`);
  set("--hero-mono", `${t.heroMono}%`);
  set("--hero-darken", `${t.heroDarken / 100}`);
  const justify = t.heroAlign === "top" ? "flex-start" : t.heroAlign === "bottom" ? "flex-end" : "center";
  set("--hero-justify", justify);

  // menu
  set("--menu-rule-style", t.menuRule === "none" ? "none" : t.menuRule);
  set("--menu-row-h", String(t.menuRowHeight));
  set("--card-opacity", String(t.cardOpacity / 100));
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Reapply CSS variables whenever any tweak changes
  React.useEffect(() => { applyTweaks(t); }, [t]);

  // When palette changes, hydrate the individual color pickers from the preset
  const setPalette = (name) => {
    const p = PALETTES[name];
    setTweak({
      palette: name,
      bg: p.bg, text: p.text, heading: p.heading,
      accent: p.accent, rule: p.rule, footerBg: p.footerBg,
    });
  };

  // Update hero copy directly in DOM (keeps page editable from the panel)
  React.useEffect(() => {
    const k = document.querySelector("[data-hero-kicker]");
    const h = document.querySelector("[data-hero-title]");
    const s = document.querySelector("[data-hero-sub]");
    if (k) k.textContent = t.kicker;
    if (h) h.innerHTML = renderHeroTitle(t.heroTitle);
    if (s) s.textContent = t.heroSub;
  }, [t.kicker, t.heroTitle, t.heroSub]);

  return (
    <TweaksPanel>
      <TweakSection label="Palette" />
      <TweakRadio label="Preset" value={t.palette}
        options={[
          { value: "classic", label: "Classic" },
          { value: "cream",   label: "Cream" },
          { value: "mist",    label: "Mist" },
          { value: "moss",    label: "Moss" },
          { value: "dark",    label: "Dark" },
        ]}
        onChange={setPalette} />
      <TweakColor label="Background" value={t.bg}      onChange={(v) => setTweak("bg", v)} />
      <TweakColor label="Body text"  value={t.text}    onChange={(v) => setTweak("text", v)} />
      <TweakColor label="Headings"   value={t.heading} onChange={(v) => setTweak("heading", v)} />
      <TweakColor label="Accent"     value={t.accent}  onChange={(v) => setTweak("accent", v)} />
      <TweakColor label="Rule"       value={t.rule}    onChange={(v) => setTweak("rule", v)} />
      <TweakColor label="Footer bg"  value={t.footerBg} onChange={(v) => setTweak("footerBg", v)} />

      <TweakSection label="Typography" />
      <TweakRadio label="Font pair" value={t.fontPair}
        options={[
          { value: "serifSans", label: "Serif+Sans" },
          { value: "serif",     label: "Serif" },
          { value: "sans",      label: "Sans" },
          { value: "mincho",    label: "明朝" },
        ]}
        onChange={(v) => setTweak("fontPair", v)} />
      <TweakSlider label="Base size"        value={t.baseSize}        min={13}  max={20}  step={1}   unit="px"
                   onChange={(v) => setTweak("baseSize", v)} />
      <TweakSlider label="Heading weight"   value={t.headingWeight}   min={300} max={700} step={50}
                   onChange={(v) => setTweak("headingWeight", v)} />
      <TweakSlider label="Heading tracking" value={t.headingTracking} min={-3}  max={15}  step={1}   unit="/100em"
                   onChange={(v) => setTweak("headingTracking", v)} />
      <TweakSlider label="Logo tracking"    value={t.logoTracking}    min={0}   max={80}  step={2}   unit="/100em"
                   onChange={(v) => setTweak("logoTracking", v)} />

      <TweakSection label="Layout" />
      <TweakSlider label="Content width" value={t.contentWidth} min={720}  max={1280} step={10} unit="px"
                   onChange={(v) => setTweak("contentWidth", v)} />
      <TweakSlider label="Section pad"   value={t.sectionPad}   min={3}    max={12}   step={0.5} unit="rem"
                   onChange={(v) => setTweak("sectionPad", v)} />
      <TweakSlider label="Radius"        value={t.radius}       min={0}    max={28}   step={1}  unit="px"
                   onChange={(v) => setTweak("radius", v)} />

      <TweakSection label="Hero" />
      <TweakSlider label="Height"     value={t.heroHeight} min={320} max={820} step={10} unit="px"
                   onChange={(v) => setTweak("heroHeight", v)} />
      <TweakSlider label="Monochrome" value={t.heroMono}   min={0}   max={100} step={1}  unit="%"
                   onChange={(v) => setTweak("heroMono", v)} />
      <TweakSlider label="Darken"     value={t.heroDarken} min={0}   max={75}  step={1}  unit="%"
                   onChange={(v) => setTweak("heroDarken", v)} />
      <TweakRadio  label="Copy align" value={t.heroAlign}
        options={[
          { value: "top",    label: "Top" },
          { value: "center", label: "Mid" },
          { value: "bottom", label: "Bot" },
        ]}
        onChange={(v) => setTweak("heroAlign", v)} />
      <TweakText label="Kicker"   value={t.kicker}    onChange={(v) => setTweak("kicker", v)} />
      <TweakText label="Title"    value={t.heroTitle} onChange={(v) => setTweak("heroTitle", v)} />
      <TweakText label="Sub copy" value={t.heroSub}   onChange={(v) => setTweak("heroSub", v)} />

      <TweakSection label="Menu" />
      <TweakRadio label="Divider" value={t.menuRule}
        options={[
          { value: "dotted", label: "Dotted" },
          { value: "dashed", label: "Dashed" },
          { value: "solid",  label: "Solid" },
          { value: "none",   label: "None" },
        ]}
        onChange={(v) => setTweak("menuRule", v)} />
      <TweakSlider label="Row height" value={t.menuRowHeight} min={1.4} max={2.6} step={0.05}
                   onChange={(v) => setTweak("menuRowHeight", v)} />
      <TweakSlider label="Card opacity" value={t.cardOpacity} min={40} max={100} step={1} unit="%"
                   onChange={(v) => setTweak("cardOpacity", v)} />
    </TweaksPanel>
  );
}

// Wrap any <em>...</em> in italic styling. Plain text otherwise.
function renderHeroTitle(s) {
  // basic escape
  const esc = (x) => x.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  // allow user to write "<em>...</em>" segments
  const parts = String(s || "").split(/(<em>[\s\S]*?<\/em>)/);
  return parts.map((p) => {
    const m = p.match(/^<em>([\s\S]*?)<\/em>$/);
    if (m) return `<em>${esc(m[1])}</em>`;
    return esc(p);
  }).join("");
}

// Apply defaults immediately so the page renders correctly even before mount
applyTweaks(TWEAK_DEFAULTS);

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