// tweaks-app.jsx
// Mounts the Tweaks panel for the cafe mock homepage.
// All tweakable values are CSS custom properties on :root, so the panel
// just calls document.documentElement.style.setProperty() — no inline-style
// rewrites, no React-driven DOM mutations.

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "classic",
  "bgColor": "#FBF7F0",
  "textColor": "#2A2520",
  "headingColor": "#1F1814",
  "accentColor": "#A6794A",
  "ruleColor": "#E5DCCB",
  "footerBg": "#1F1814",

  "fontPair": "serif_sans",
  "baseSize": 16,
  "headingWeight": 500,
  "headingTracking": -2,
  "logoTracking": 32,

  "contentWidth": 1100,
  "sectionGap": 6,
  "radius": 4,

  "heroHeight": 560,
  "heroMono": 0,
  "heroDarken": 30,
  "heroAlign": "center",
  "heroKicker": "Est. — Workshop Mock",
  "heroTitle": "Slow mornings,\nbright coffee.",
  "heroSubcopy": "光と静けさのある一杯を。日々の途中に立ち寄れる、小さな休符のような場所です。",

  "menuRule": "dotted",
  "menuRowHeight": 14,
  "cardOpacity": 92
}/*EDITMODE-END*/;

// Palette presets — switching one writes through to the six individual colors.
const PALETTES = {
  classic: { bgColor: "#FBF7F0", textColor: "#2A2520", headingColor: "#1F1814", accentColor: "#A6794A", ruleColor: "#E5DCCB", footerBg: "#1F1814" },
  cream:   { bgColor: "#F4ECDC", textColor: "#33291E", headingColor: "#241A0F", accentColor: "#B8895A", ruleColor: "#E0D2B6", footerBg: "#241A0F" },
  mist:    { bgColor: "#F2F1EC", textColor: "#28302E", headingColor: "#172524", accentColor: "#5B7D6F", ruleColor: "#D8DDD7", footerBg: "#172524" },
  moss:    { bgColor: "#EEEFE6", textColor: "#2A2D22", headingColor: "#1A1D14", accentColor: "#6B7B3F", ruleColor: "#D4D7C5", footerBg: "#1A1D14" },
  dark:    { bgColor: "#181613", textColor: "#E8E2D5", headingColor: "#F2EBDA", accentColor: "#D9B27C", ruleColor: "#3A332A", footerBg: "#0E0C0A" },
};

const FONT_PAIRS = {
  serif_sans: { heading: "'Fraunces', Georgia, serif",            body: "'Inter', system-ui, sans-serif",          jp: "'Shippori Mincho', 'Hiragino Mincho ProN', serif" },
  serif:      { heading: "'Fraunces', Georgia, serif",            body: "'Fraunces', Georgia, serif",              jp: "'Shippori Mincho', 'Hiragino Mincho ProN', serif" },
  sans:       { heading: "'Inter', system-ui, sans-serif",        body: "'Inter', system-ui, sans-serif",          jp: "'Inter', 'Hiragino Kaku Gothic ProN', sans-serif" },
  mincho:     { heading: "'Shippori Mincho', Georgia, serif",     body: "'Shippori Mincho', Georgia, serif",       jp: "'Shippori Mincho', 'Hiragino Mincho ProN', serif" },
};

// Apply every CSS variable derived from the current tweak values.
function applyTweaks(t) {
  const r = document.documentElement.style;
  r.setProperty('--bg', t.bgColor);
  r.setProperty('--text', t.textColor);
  r.setProperty('--heading', t.headingColor);
  r.setProperty('--accent', t.accentColor);
  r.setProperty('--rule', t.ruleColor);
  r.setProperty('--footer-bg', t.footerBg);

  const pair = FONT_PAIRS[t.fontPair] || FONT_PAIRS.serif_sans;
  r.setProperty('--font-heading', pair.heading);
  r.setProperty('--font-body', pair.body);
  r.setProperty('--font-jp', pair.jp);

  r.setProperty('--base-size', t.baseSize + 'px');
  r.setProperty('--heading-weight', String(t.headingWeight));
  r.setProperty('--heading-tracking', (t.headingTracking / 100) + 'em');
  r.setProperty('--logo-tracking', (t.logoTracking / 100) + 'em');

  r.setProperty('--content-width', t.contentWidth + 'px');
  r.setProperty('--section-gap', t.sectionGap + 'rem');
  r.setProperty('--radius', t.radius + 'px');

  r.setProperty('--hero-h', t.heroHeight + 'px');
  r.setProperty('--hero-mono', (t.heroMono / 100));
  r.setProperty('--hero-darken', (t.heroDarken / 100));
  const align = { top: 'flex-start', center: 'center', bottom: 'flex-end' }[t.heroAlign] || 'center';
  r.setProperty('--hero-align', align);

  const ruleStyle = t.menuRule === 'none' ? 'none' : t.menuRule;
  r.setProperty('--menu-rule', ruleStyle);
  r.setProperty('--menu-row-pad', (t.menuRowHeight / 10) + 'rem');
  r.setProperty('--card-opacity', (t.cardOpacity / 100));

  // Hero copy — written into data attributes / textContent of fixed nodes.
  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.heroKicker;
  if (h) h.innerHTML = renderHeroTitle(t.heroTitle);
  if (s) s.textContent = t.heroSubcopy;
}

// Renders title text with line breaks; wraps the second line in <em> for that
// editorial italic flourish.
function renderHeroTitle(raw) {
  const lines = (raw || '').split(/\n+/);
  return lines.map((ln, i) => {
    const safe = ln.replace(/[<>&]/g, c => ({ '<': '&lt;', '>': '&gt;', '&': '&amp;' }[c]));
    if (i === 1) return `<em>${safe}</em>`;
    return safe;
  }).join('<br/>');
}

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

  // Re-apply on every change. Runs once on mount so the persisted defaults
  // hit the DOM before paint.
  React.useEffect(() => { applyTweaks(t); }, [t]);

  const applyPalette = (name) => {
    const p = PALETTES[name];
    if (!p) { setTweak('palette', name); return; }
    setTweak({ palette: name, ...p });
  };

  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="Palette" />
      <TweakRadio
        label="Preset"
        value={t.palette}
        options={[
          { value: 'classic', label: 'Classic' },
          { value: 'cream',   label: 'Cream' },
          { value: 'mist',    label: 'Mist' },
        ]}
        onChange={applyPalette}
      />
      <TweakRadio
        label=" "
        value={t.palette}
        options={[
          { value: 'moss', label: 'Moss' },
          { value: 'dark', label: 'Dark' },
        ]}
        onChange={applyPalette}
      />
      <TweakColor label="Background"   value={t.bgColor}      onChange={(v) => setTweak('bgColor', v)} />
      <TweakColor label="Body text"    value={t.textColor}    onChange={(v) => setTweak('textColor', v)} />
      <TweakColor label="Headings"     value={t.headingColor} onChange={(v) => setTweak('headingColor', v)} />
      <TweakColor label="Accent"       value={t.accentColor}  onChange={(v) => setTweak('accentColor', v)} />
      <TweakColor label="Rules"        value={t.ruleColor}    onChange={(v) => setTweak('ruleColor', v)} />
      <TweakColor label="Footer bg"    value={t.footerBg}     onChange={(v) => setTweak('footerBg', v)} />

      <TweakSection label="Typography" />
      <TweakRadio
        label="Pair"
        value={t.fontPair}
        options={[
          { value: 'serif_sans', label: 'Serif+Sans' },
          { value: 'serif',      label: 'Serif' },
        ]}
        onChange={(v) => setTweak('fontPair', v)}
      />
      <TweakRadio
        label=" "
        value={t.fontPair}
        options={[
          { value: 'sans',   label: 'Sans' },
          { value: 'mincho', label: '明朝' },
        ]}
        onChange={(v) => setTweak('fontPair', v)}
      />
      <TweakSlider label="Base size"        value={t.baseSize}        min={13}  max={20}  unit="px" onChange={(v) => setTweak('baseSize', v)} />
      <TweakSlider label="Heading weight"   value={t.headingWeight}   min={300} max={700} step={100} onChange={(v) => setTweak('headingWeight', v)} />
      <TweakSlider label="Heading tracking" value={t.headingTracking} min={-3}  max={15}  unit="/100em" onChange={(v) => setTweak('headingTracking', v)} />
      <TweakSlider label="Logo tracking"    value={t.logoTracking}    min={0}   max={80}  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 gap"   value={t.sectionGap}   min={3}   max={12}   step={0.5} unit="rem" onChange={(v) => setTweak('sectionGap', v)} />
      <TweakSlider label="Radius"        value={t.radius}       min={0}   max={28}   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} unit="%" onChange={(v) => setTweak('heroMono', v)} />
      <TweakSlider label="Darken"     value={t.heroDarken} min={0} max={75}  unit="%" onChange={(v) => setTweak('heroDarken', v)} />
      <TweakRadio
        label="Copy position"
        value={t.heroAlign}
        options={[
          { value: 'top',    label: 'Top' },
          { value: 'center', label: 'Mid' },
          { value: 'bottom', label: 'Btm' },
        ]}
        onChange={(v) => setTweak('heroAlign', v)}
      />
      <TweakText label="Kicker"   value={t.heroKicker}  onChange={(v) => setTweak('heroKicker', v)} />
      <TweakText label="Title"    value={t.heroTitle}   onChange={(v) => setTweak('heroTitle', v)} />
      <TweakText label="Subcopy"  value={t.heroSubcopy} onChange={(v) => setTweak('heroSubcopy', v)} />

      <TweakSection label="Menu" />
      <TweakRadio
        label="Rule"
        value={t.menuRule}
        options={[
          { value: 'dotted', label: 'Dot' },
          { value: 'dashed', label: 'Dash' },
          { value: 'solid',  label: 'Line' },
          { value: 'none',   label: 'None' },
        ]}
        onChange={(v) => setTweak('menuRule', v)}
      />
      <TweakSlider label="Row height"   value={t.menuRowHeight} min={6}  max={26} unit="/10rem" onChange={(v) => setTweak('menuRowHeight', v)} />
      <TweakSlider label="Card opacity" value={t.cardOpacity}   min={50} max={100} unit="%" onChange={(v) => setTweak('cardOpacity', v)} />
    </TweaksPanel>
  );
}

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