// app.jsx — simulation, state, panel, timeline, tweaks.

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ── Simulation model ─────────────────────────────────────────────────────────
// Inputs: hour (0-24), weather, buildingType, loadProfile, scenario, prevSoc
// Output: { pv, load, pvToHouse, pvToBattery, batteryToHouse, genToBattery,
//           genToHouse, genRunning, soc, hour, tod, mode, modeLabel }

const SOC_GEN_START = 0.25;   // Generator kicks in when battery <= 25%
const SOC_GEN_STOP  = 0.80;   // Generator stops at 80%
const BATTERY_KWH   = 15;
const HOUSE_BASE_KW = { low: 0.4, normal: 0.9, high: 1.6 };
const COMMERCIAL_BASE_KW = { low: 2.0, normal: 4.5, high: 8.0 };
const PV_PEAK_KW    = { house: 8.0, commercial: 24.0 };
const GEN_MAX_KW    = 12.0;

function pvProfile(hour, weather) {
  if (hour < 6 || hour > 20) return 0;
  // Bell curve, peak at 13.
  const x = (hour - 13) / 5.5;
  let y = Math.exp(-x * x * 1.2);
  // Auto mode: clear sky until 13:45, then heavy clouds roll in (production drops to ~0)
  if (weather === 'auto') {
    if (hour >= 13.25 && hour < 13.75) y *= (13.75 - hour) / 0.5; // sharp ramp-down 13:15→13:45
    else if (hour >= 13.75) y *= 0.05;                            // overcast residual
  }
  if (weather === 'cloudy') y *= 0.35 + 0.15 * Math.sin(hour * 1.3);
  if (weather === 'overcast') y *= 0.12;
  return Math.max(0, y);
}

function loadProfile(hour, baseKw) {
  // Profile designed to tell a story:
  //  6-9   morning ramp
  //  9-14  day baseline
  //  14-18 sustained heavy afternoon load (clouds rolled in, AC + appliances)
  //  18-22 evening plateau, then decay
  //  22-6  night base
  let m = 0.5;
  if (hour >= 6 && hour < 9) m = 0.7 + (hour - 6) * 0.13;       // 0.70 → 1.09
  else if (hour >= 9 && hour < 14) m = 0.95;
  else if (hour >= 14 && hour < 18) {
    // Sustained heavy load (AC + appliances + cooking) plateau ~3.0× with
    // peak ~3.5× around 16:00. With baseKw≈0.9 kW this drains the 15 kWh
    // battery from 100 % to ~25 % across the four hours, so the genset
    // trips right at 18:00.
    const x = (hour - 16.0) / 2.0;
    m = 3.00 + 0.50 * Math.exp(-x * x * 1.4);
  }
  else if (hour >= 18 && hour < 22) m = 1.40 - (hour - 18) * 0.20; // taper after gen kicks in
  else m = 0.5;
  return baseKw * m;
}

function timeOfDay(hour) {
  if (hour < 5 || hour >= 21) return 'night';
  if (hour < 7) return 'dawn';
  if (hour < 18) return 'day';
  return 'dusk';
}

function simulate(hour, prevSoc, tweaks) {
  const isCommercial = tweaks.buildingType === 'commercial';
  const baseKw = (isCommercial ? COMMERCIAL_BASE_KW : HOUSE_BASE_KW)[tweaks.loadProfile] || 0.9;
  const pvPeak = PV_PEAK_KW[isCommercial ? 'commercial' : 'house'];
  // In auto-scenario the cloud rolls in at 15:00 and stays — PV essentially
  // collapses for the rest of the day so the battery is forced to cover the
  // afternoon load until the genset trips.
  let effWeather = tweaks.weather;
  if (tweaks.scenario === 'auto') {
    effWeather = hour >= 13.25 ? 'auto' : 'clear';
  }
  const pv = pvProfile(hour, effWeather) * pvPeak;
  const load = loadProfile(hour, baseKw);

  // Allocate PV first to load, surplus to battery
  let pvToHouse = Math.min(pv, load);
  let pvToBattery = Math.max(0, pv - pvToHouse);
  let deficit = Math.max(0, load - pvToHouse); // load not covered by PV

  // Battery covers deficit if SoC > min
  let batteryToHouse = 0;
  let soc = prevSoc;

  // Decide generator state — hysteresis: start when SOC drops to threshold,
  // keep running until SOC reaches stop threshold.
  let genRunning = tweaks.scenario === 'gen-on' ? true
    : tweaks.scenario === 'gen-off' ? false
    : (prevSoc <= SOC_GEN_START && deficit > 0.1) || (prevSoc < SOC_GEN_STOP && tweaks._genWasRunning);

  // Manual override modes
  if (tweaks.scenario === 'sunny') genRunning = false;
  if (tweaks.scenario === 'evening') genRunning = false;
  if (tweaks.scenario === 'low-battery') genRunning = true;

  let genToHouse = 0;
  let genToBattery = 0;

  if (genRunning) {
    // Generator covers deficit, then charges battery
    genToHouse = Math.min(deficit, GEN_MAX_KW);
    deficit -= genToHouse;
    const chargeRoom = (1 - prevSoc) * BATTERY_KWH * 4; // simplified
    genToBattery = Math.min(GEN_MAX_KW - genToHouse, Math.max(0, chargeRoom));
    genToBattery = Math.min(genToBattery, 6); // realistic charge rate
  } else if (prevSoc > 0.05) {
    batteryToHouse = Math.min(deficit, 5);
  }

  // Update SoC (per simulated hour-step; we'll scale outside)
  // ΔkWh = (charge − discharge) * dt; we use dt = 1h equivalents and small step factor
  // Actually we'll do this update outside loop (per-tick). Return rates.

  // Mode label — derived strictly from active flows shown in the scene.
  // Priority: generator (when running) > PV-driven > battery-only > idle.
  let mode = 'idle';
  let modeLabel = 'Tryb spoczynku';
  const pvActive = pv > 0.1;
  const battDischarge = batteryToHouse > 0.05;
  const battCharge = (pvToBattery + genToBattery) > 0.05;

  if (genRunning) {
    if (genToBattery > 0.1 && genToHouse > 0.1) { mode = 'gen-mixed'; modeLabel = 'Generator zasila budynek i magazyn'; }
    else if (genToBattery > 0.1)                { mode = 'gen-charging'; modeLabel = 'Generator ładuje magazyn'; }
    else                                        { mode = 'gen-direct';   modeLabel = 'Generator zasila budynek'; }
  } else if (pvActive) {
    if (pvToBattery > 0.1 && pvToHouse > 0.1)   { mode = 'pv-mixed';    modeLabel = 'PV zasila budynek i ładuje magazyn'; }
    else if (pvToBattery > 0.1)                 { mode = 'pv-charging'; modeLabel = 'PV ładuje magazyn'; }
    else if (battDischarge)                     { mode = 'pv-plus-batt';modeLabel = 'PV i magazyn zasilają budynek'; }
    else                                        { mode = 'pv-direct';   modeLabel = 'PV zasila budynek'; }
  } else if (battDischarge) {
    mode = 'battery'; modeLabel = 'Magazyn zasila budynek';
  } else if (battCharge) {
    mode = 'pv-charging'; modeLabel = 'PV ładuje magazyn';
  }

  return {
    pv, load,
    pvToHouse, pvToBattery, batteryToHouse,
    genToHouse, genToBattery,
    genRunning,
    soc,
    hour,
    tod: timeOfDay(hour),
    mode, modeLabel,
  };
}

// ── Hour formatting ──────────────────────────────────────────────────────────
function fmtHour(h) {
  const hh = Math.floor(h);
  const mm = Math.floor((h - hh) * 60);
  return `${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}`;
}

// ── PV + Load silhouettes on timeline ────────────────────────────────────────
function TimelineLoadCurve({ buildingType, loadProfileKey, scenario }) {
  const HOUSE_BASE_KW = { low: 0.45, normal: 0.9, high: 1.6 };
  const COMMERCIAL_BASE_KW = { low: 4.0, normal: 7.5, high: 12.0 };
  const isCommercial = buildingType === 'commercial';
  const baseKw = (isCommercial ? COMMERCIAL_BASE_KW : HOUSE_BASE_KW)[loadProfileKey] || 0.9;
  const peakKw = isCommercial ? 16 : 4; // y-axis scale
  const points = [];
  for (let h = 0; h <= 24; h += 0.25) {
    const load = loadProfile(h, baseKw);
    const x = (h / 24) * 100;
    const y = 100 - Math.min(1, load / peakKw) * 80;
    points.push(`${x.toFixed(2)},${y.toFixed(2)}`);
  }
  return (
    <svg className="timeline-load" viewBox="0 0 100 100" preserveAspectRatio="none">
      <path d={`M${points.join(' L')}`} fill="none" stroke="oklch(0.78 0.20 22)"
        strokeWidth="2" opacity="1" strokeDasharray="4 3" vectorEffect="non-scaling-stroke" />
    </svg>
  );
}

function TimelinePVCurve({ weather, scenario }) {
  const points = [];
  for (let h = 0; h <= 24; h += 0.25) {
    let effW = weather;
    if (scenario === 'auto') {
      effW = h >= 13.25 ? 'auto' : 'clear';
    }
    const v = pvProfile(h, effW);
    const x = (h / 24) * 100;
    const y = 100 - v * 90;
    points.push(`${x},${y}`);
  }
  const path = `M0,100 L${points.join(' L')} L100,100 Z`;
  return (
    <svg className="timeline-pv" viewBox="0 0 100 100" preserveAspectRatio="none">
      <path d={path} fill="oklch(0.74 0.14 75)" opacity="0.20" />
      <path d={`M${points.join(' L')}`} fill="none" stroke="oklch(0.74 0.14 75)" strokeWidth="2" opacity="0.85" vectorEffect="non-scaling-stroke" />
    </svg>
  );
}

// ── Main App ─────────────────────────────────────────────────────────────────
// Time-warp: speed up dull hours so the user doesn't watch the SoC sag for
// real-time minutes overnight. Daytime + the action window stays at 1×.
function timeWarp(hour) {
  if (hour >= 22 || hour < 5) return 5;     // overnight: 5×
  if (hour >= 5 && hour < 7)   return 2.5;  // pre-dawn ramp
  if (hour >= 9 && hour < 13)  return 1.6;  // sunny midday (battery fully charged, nothing to see)
  return 1;
}

function App() {
  // Tweaks removed — values fixed.
  const tweaks = {
    scenario: 'auto',
    weather: 'clear',
    buildingType: 'house',
    loadProfile: 'normal',
    showFlows: true,
    showLabels: true,
    speed: 1,
  };

  // Time control: virtual hour 0..24, ticking
  const [hour, setHour] = useState(13.0);
  const [playing, setPlaying] = useState(true);
  const [soc, setSoc] = useState(0.65);
  const [menuOpen, setMenuOpen] = useState(false);
  const menuRef = useRef(null);
  useEffect(() => {
    if (!menuOpen) return;
    const onDocClick = (e) => { if (menuRef.current && !menuRef.current.contains(e.target)) setMenuOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setMenuOpen(false); };
    document.addEventListener('mousedown', onDocClick);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDocClick); document.removeEventListener('keydown', onKey); };
  }, [menuOpen]);
  const prevSimRef = useRef(null);
  const genWasRunningRef = useRef(false);

  // Tick the clock
  useEffect(() => {
    if (!playing) return;
    const id = setInterval(() => {
      setHour((h) => {
        // Speed: full day in ~60s at speed=1, with time-warp in dull hours
        const step = (24 / 60 / 10) * tweaks.speed * timeWarp(h);
        let next = h + step;
        if (next >= 24) next = 0;
        return next;
      });
    }, 100);
    return () => clearInterval(id);
  }, [playing, tweaks.speed]);

  // Apply scenario presets — they snap the clock to a meaningful time and force conditions
  useEffect(() => {
    let h = null;
    if (tweaks.scenario === 'sunny')             h = 13;
    else if (tweaks.scenario === 'evening')      h = 20;
    else if (tweaks.scenario === 'night')        h = 2;
    else if (tweaks.scenario === 'low-battery')  h = 4;
    if (h === null) return;
    setHour(h);
    if (tweaks.scenario === 'low-battery') {
      setSoc(Math.min(0.18, socForHour(h, tweaks)));
    } else {
      setSoc(socForHour(h, tweaks));
    }
    genWasRunningRef.current = false;
  }, [tweaks.scenario]);

  // Compute simulation each tick
  const sim = useMemo(() => {
    const tweakInternal = { ...tweaks, _genWasRunning: genWasRunningRef.current };
    const result = simulate(hour, soc, tweakInternal);
    return { ...result, soc };
  }, [hour, soc, tweaks]);

  // SoC integration: drive it from its own interval that reads the latest
  // sim/tweaks via refs, so the clock tick (which re-creates the sim memo
  // every 100 ms) doesn't keep cancelling a pending setTimeout before it
  // commits the SoC update.
  const simRef = useRef(sim);
  const tweaksRef = useRef(tweaks);
  const hourRef = useRef(hour);
  useEffect(() => { simRef.current = sim; }, [sim]);
  useEffect(() => { tweaksRef.current = tweaks; }, [tweaks]);
  useEffect(() => { hourRef.current = hour; }, [hour]);

  useEffect(() => {
    if (!playing) return;
    const id = setInterval(() => {
      const s = simRef.current;
      const tw = tweaksRef.current;
      const h = hourRef.current;
      const simHoursPerTick = (24 / 60 / 10) * tw.speed * timeWarp(h);
      const netKw = (s.pvToBattery + s.genToBattery) - s.batteryToHouse;
      const deltaKwh = netKw * simHoursPerTick;
      setSoc((prev) => {
        let n = prev + deltaKwh / BATTERY_KWH;
        return Math.max(0.02, Math.min(1, n));
      });
    }, 100);
    return () => clearInterval(id);
  }, [playing]);

  // Track gen state for hysteresis
  useEffect(() => {
    genWasRunningRef.current = sim.genRunning;
  }, [sim.genRunning]);

  // Event detection
  useEffect(() => {
    prevSimRef.current = sim;
  }, [sim.mode, sim.genRunning]);

  // Compute a SoC that is consistent with a given hour by running a full-day
  // simulation from a sane starting point (06:00, SoC=0.55) up to that hour.
  // This avoids the "it's 02:00 but battery is full because we just teleported
  // there from solar noon" inconsistency when the user scrubs the timeline.
  const socForHour = useCallback((targetHour, tw) => {
    const dt = 0.1; // 6-minute steps
    let s = 0.55;
    let h = 6.0;
    let genWas = false;
    // Walk forward; if target is before 06:00, wrap through midnight
    const totalH = (targetHour - h + 24) % 24;
    const steps = Math.round(totalH / dt);
    for (let i = 0; i < steps; i++) {
      const result = simulate(h, s, { ...tw, _genWasRunning: genWas });
      const net = (result.pvToBattery + result.genToBattery) - result.batteryToHouse;
      s = Math.max(0.05, Math.min(1, s + (net * dt) / BATTERY_KWH));
      genWas = result.genRunning;
      h = (h + dt) % 24;
    }
    return s;
  }, []);

  // Click on timeline to seek — also re-derive a consistent SoC for the new hour
  const onSeek = useCallback((e) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const t = (e.clientX - rect.left) / rect.width;
    const newHour = Math.max(0, Math.min(23.99, t * 24));
    setHour(newHour);
    // Scenario "low-battery" forces a depleted state; otherwise compute realistic SoC
    if (tweaks.scenario === 'low-battery') {
      setSoc(Math.min(0.22, socForHour(newHour, tweaks)));
    } else {
      setSoc(socForHour(newHour, tweaks));
    }
    genWasRunningRef.current = false;
  }, [tweaks, socForHour]);

  return (
    <>
    <div id="top" className="stage" data-tod={sim.tod}>
      {/* TOPBAR */}
      <header className="topbar">
        <div className="brand-wrap" ref={menuRef}>
          <button className={`brand brand-trigger${menuOpen ? ' open' : ''}`}
                  onClick={() => setMenuOpen((o) => !o)}
                  aria-expanded={menuOpen} aria-haspopup="menu" type="button">
            <div className="brand-mark">0G</div>
            <div className="brand-text">
              <div className="brand-name">zerogrid<span className="tld">.pl</span></div>
              <h1>Wizualizacja systemu off-grid · live</h1>
            </div>
            <svg className="brand-chevron" width="11" height="11" viewBox="0 0 12 12" aria-hidden="true">
              <path d="M2.5 4.5 L6 8 L9.5 4.5" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          </button>
          {menuOpen && (
            <div className="brand-menu" role="menu">
              <div className="brand-menu-header">
                <div className="brand-mark brand-mark-lg">0G</div>
                <div>
                  <div className="brand-menu-title">zerogrid.pl</div>
                  <div className="brand-menu-tag">Systemy off-grid · PV + magazyn + generator</div>
                </div>
              </div>
              {[
                { href: '#top', label: 'Strona główna', sub: 'Symulator on-line', current: true },
                { href: '#oferta', label: 'Oferta', sub: 'PV · magazyny · generatory' },
                { href: '#jak-dziala', label: 'Jak to działa', sub: 'Logika sterownika' },
                { href: '#realizacje', label: 'Realizacje', sub: 'Wdrożenia · case studies' },
                { href: '#kontakt', label: 'Kontakt', sub: 'Bezpłatna wycena' },
              ].map((item) => (
                <a key={item.label} className={`brand-menu-item${item.current ? ' is-current' : ''}`}
                   href={item.href} role="menuitem"
                   onClick={(e) => {
                     setMenuOpen(false);
                     if (item.href.startsWith('#')) {
                       e.preventDefault();
                       const id = item.href.slice(1);
                       if (id === 'top') {
                         window.scrollTo({ top: 0, behavior: 'smooth' });
                       } else {
                         document.getElementById(id)?.scrollIntoView({ behavior: 'smooth', block: 'start' });
                       }
                     }
                   }}>
                  <div>
                    <div className="brand-menu-label">{item.label}</div>
                    <div className="brand-menu-sub">{item.sub}</div>
                  </div>
                  {item.current
                    ? <span className="brand-menu-pill">tutaj</span>
                    : <svg width="10" height="10" viewBox="0 0 10 10" aria-hidden="true"><path d="M3 1 L7 5 L3 9" fill="none" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/></svg>}
                </a>
              ))}
              <div className="brand-menu-foot">
                <span>v2.4 · live demo</span>
                <a href="https://zerogrid.pl/kontakt" className="brand-menu-cta">Bezpłatna wycena →</a>
              </div>
            </div>
          )}
        </div>
        <div className="topbar-meta">
          <span><span className="dot"></span>System aktywny</span>
          <span className="mono">{tweaks.buildingType === 'commercial' ? 'OBIEKT KOMERCYJNY' : 'DOM JEDNORODZINNY'}</span>
          <span className="mono">v2.4</span>
        </div>
      </header>

      {/* SCENE */}
      <div className="scene-wrap">
        <div className="legend">
          <div className="legend-row">
            <span className="legend-swatch" style={{ background: 'var(--solar)' }}></span>
            <span>Energia z PV</span>
          </div>
          <div className="legend-row">
            <span className="legend-swatch" style={{ background: 'var(--battery)' }}></span>
            <span>Energia z magazynu</span>
          </div>
          <div className="legend-row">
            <span className="legend-swatch" style={{ background: 'var(--gen)' }}></span>
            <span>Energia z generatora</span>
          </div>
        </div>

        <Scene sim={sim} tweaks={tweaks} />

        <div className="scene-caption">
          <div className="scene-caption-inner">
            <div className="eyebrow">Aktualnie · {fmtHour(sim.hour)}</div>
            <h2>{sim.modeLabel}</h2>
          </div>
        </div>
      </div>

      {/* PANEL */}
      <aside className="panel">
        <div className="panel-section">
          <h3>Stan systemu</h3>
          <div className="state-pill">
            <span className="pulse"></span>
            <span>{sim.modeLabel}</span>
          </div>
          <p className="state-desc">{describeMode(sim, tweaks)}</p>
        </div>

        <div className="panel-section">
          <h3>Przepływ energii</h3>
          <div className="stat-grid">
            <div className="stat solar">
              <div className="label">Produkcja PV</div>
              <div className="value">{sim.pv.toFixed(1)}<span className="unit">kW</span></div>
            </div>
            <div className="stat load">
              <div className="label">Pobór</div>
              <div className="value">{sim.load.toFixed(1)}<span className="unit">kW</span></div>
            </div>
            <div className="stat battery">
              <div className="label">{sim.batteryToHouse > 0.05 ? 'Z magazynu' : (sim.pvToBattery + sim.genToBattery > 0.05) ? 'Ładowanie' : 'Magazyn'}</div>
              <div className="value">
                {sim.batteryToHouse > 0.05 ? sim.batteryToHouse.toFixed(1)
                  : (sim.pvToBattery + sim.genToBattery).toFixed(1)}
                <span className="unit">kW</span>
              </div>
            </div>
            <div className="stat gen">
              <div className="label">Generator</div>
              <div className="value">
                {sim.genRunning ? (sim.genToBattery + sim.genToHouse).toFixed(1) : '0.0'}
                <span className="unit">kW</span>
              </div>
            </div>
          </div>
        </div>

        <div className="panel-section">
          <h3>Magazyn energii</h3>
          <div className="battery-card">
            <div className="row">
              <span className="label">SoC</span>
              <span className="pct">{Math.round(sim.soc * 100)}%</span>
            </div>
            <div className="battery-bar">
              <div className="battery-fill" style={{
                width: `${sim.soc * 100}%`,
                background: sim.soc < 0.25 ? 'var(--warn)' : 'var(--battery)'
              }}></div>
            </div>
            <div className="battery-meta">
              <span>{(sim.soc * BATTERY_KWH).toFixed(1)} / {BATTERY_KWH} kWh</span>
              <span>
                {sim.batteryToHouse > 0.05 ? `−${sim.batteryToHouse.toFixed(1)} kW`
                : (sim.pvToBattery + sim.genToBattery) > 0.05 ? `+${(sim.pvToBattery + sim.genToBattery).toFixed(1)} kW`
                : '— idle'}
              </span>
            </div>
          </div>
        </div>

      </aside>

      {/* TIMELINE */}
      <div className="timeline">
        <div className="timeline-head">
          <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
            <button className="play-btn" onClick={() => setPlaying((p) => !p)} title={playing ? 'Pauza' : 'Odtwórz'}>
              {playing ? (
                <svg width="12" height="12" viewBox="0 0 12 12"><rect x="2" y="1" width="3" height="10" fill="currentColor"/><rect x="7" y="1" width="3" height="10" fill="currentColor"/></svg>
              ) : (
                <svg width="12" height="12" viewBox="0 0 12 12"><polygon points="2,1 11,6 2,11" fill="currentColor"/></svg>
              )}
            </button>
            <div className="clock mono">{fmtHour(sim.hour)}</div>
            <div className="day-meta mono" style={{ textTransform: 'uppercase', letterSpacing: '0.08em', fontSize: 10.5 }}>
              {sim.tod === 'night' ? 'NOC' : sim.tod === 'dawn' ? 'ŚWIT' : sim.tod === 'dusk' ? 'ZMIERZCH' : 'DZIEŃ'} ·
              {' '}{tweaks.weather === 'clear' ? 'BEZCHMURNIE' : tweaks.weather === 'cloudy' ? 'POCHMURNO' : 'ZACHMURZENIE'}
            </div>
          </div>
          <div className="preset-row">
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 10.5,
              letterSpacing: '0.10em', textTransform: 'uppercase', color: 'var(--ink-2)',
              fontFamily: 'JetBrains Mono, monospace' }}>
              <span>Tryb 24h auto</span>
              <span style={{
                width: 6, height: 6, borderRadius: '50%',
                background: sim.genRunning ? 'oklch(0.74 0.20 30)'
                  : sim.pv > 0.1 ? 'oklch(0.78 0.16 75)'
                  : 'oklch(0.65 0.16 160)',
                boxShadow: '0 0 8px currentColor',
              }} />
            </div>
          </div>
        </div>
        <div className="timeline-track" onClick={onSeek}>
          <div className="timeline-bg"></div>
          <TimelinePVCurve weather={tweaks.weather} scenario={tweaks.scenario} />
          <TimelineLoadCurve buildingType={tweaks.buildingType} loadProfileKey={tweaks.loadProfile} scenario={tweaks.scenario} />
          <div className="timeline-legend">
            <span className="lg-item"><i className="lg-sw lg-pv"></i>PV</span>
            <span className="lg-item"><i className="lg-sw lg-load"></i>Pobór</span>
          </div>
          <div className="timeline-hours">
            {Array.from({ length: 24 }).map((_, i) => (
              <div key={i} className="timeline-hour" data-h={String(i).padStart(2, '0')}></div>
            ))}
          </div>
          <div className="timeline-playhead" style={{ left: `${(sim.hour / 24) * 100}%` }}></div>
        </div>
      </div>

    </div>

    {/* ───────── BELOW THE FOLD ───────── */}
    <main className="below-fold">
      <section id="oferta" className="bf-section">
        <div className="bf-eyebrow">Oferta</div>
        <h2 className="bf-h2">Trzy elementy, jedna logika.</h2>
        <p clasisName="bf-lede">Projektujemy kompletne układy off‑grid: panele fotowoltaiczne, magazyn energii i generator wspomagający. Wszystko sterowane jednym kontrolerem, który priorytetyzuje słońce, w nocu korzysta z baterii, a generator uruchamia tylko wtedy, gdy to naprawdę konieczne.</p>
        <div className="bf-grid bf-grid-3">
          <div className="bf-card">
            <div className="bf-card-tag">PV</div>
            <h3>Panele fotowoltaiczne</h3>
            <p>Dobierane pod profil zużycia i nasłonecznienie. Moc 5–40 kWp, z optymalizatorami dla zacienionych dachów.</p>
          </div>
          <div className="bf-card">
            <div className="bf-card-tag">BESS</div>
            <h3>Magazyn energii</h3>
            <p>Baterie LFP 10–80 kWh. Bezpieczne, długowieczne (6 000+ cykli) i skalowane modułowo wraz z potrzebami.</p>
          </div>
          <div className="bf-card">
            <div className="bf-card-tag">GEN</div>
            <h3>Generator wspomagający</h3>
            <p>Diesel lub LPG, 6–20 kW. Uruchamiany automatycznie tylko przy niskim SoC, pracuje krótko i wydajnie.</p>
          </div>
        </div>
      </section>

      <section id="jak-dziala" className="bf-section bf-section-alt">
        <div className="bf-eyebrow">Jak to działa</div>
        <h2 className="bf-h2">Sterownik decyduje co sekundę.</h2>
        <p className="bf-lede">Powyżej widzisz tę logikę na żywo — każda zmiana godziny, pogody czy obciążenia wymusza inny tryb pracy. Cztery zasady:</p>
        <ol className="bf-steps">
          <li><strong>Słońce ma priorytet.</strong> PV zasila budynek bezpośrednio. Nadwyżka idzie do magazynu.</li>
          <li><strong>Magazyn pracuje wieczorem i w nocy.</strong> Energia zgromadzona w dzień zasila budynek aż do świtu.</li>
          <li><strong>Generator startuje awaryjnie.</strong> Tylko gdy SoC spadnie do 25%. Wyłącza się po naładowaniu do ~75%.</li>
          <li><strong>Brak sieci, brak rachunków.</strong> System jest w pełni autonomiczny — nie potrzebuje przyłącza energetycznego.</li>
        </ol>
      </section>

      <section id="realizacje" className="bf-section">
        <div className="bf-eyebrow">Realizacje</div>
        <h2 className="bf-h2">Wybrane wdrożenia.</h2>
        <div className="bf-grid bf-grid-3">
          <div className="bf-case">
            <div className="bf-case-meta">Mazury · 2024</div>
            <h3>Dom całoroczny</h3>
            <p>12 kWp PV · 30 kWh magazyn · 8 kW generator. Generator uruchamia się średnio 11 dni w roku, głównie w grudniu.</p>
          </div>
          <div className="bf-case">
            <div className="bf-case-meta">Bieszczady · 2023</div>
            <h3>Pensjonat 14 osób</h3>
            <p>24 kWp PV · 60 kWh magazyn · 16 kW generator. Pełna autonomia od marca do października bez uruchamiania generatora.</p>
          </div>
          <div className="bf-case">
            <div className="bf-case-meta">Kaszuby · 2024</div>
            <h3>Warsztat stolarski</h3>
            <p>18 kWp PV · 40 kWh magazyn · 12 kW generator. Obciążenie szczytowe przy obrabiarkach pokrywa magazyn + PV jednocześnie.</p>
          </div>
        </div>
      </section>

      <section id="kontakt" className="bf-section bf-section-alt bf-section-cta">
        <div className="bf-eyebrow">Kontakt</div>
        <h2 className="bf-h2">Bezpłatna wycena projektu.</h2>
        <p className="bf-lede">Prześlij nam lokalizację i przybliżone zużycie — w ciągu 48 h otrzymasz wstępny dobór mocy PV, pojemności magazynu i generatora oraz szacunek inwestycji.</p>
        <div className="bf-cta-row">
          <a className="bf-btn bf-btn-primary" href="mailto:kontakt@zerogrid.pl">kontakt@zerogrid.pl</a>
          <a className="bf-btn bf-btn-ghost" href="tel:+48000000000">+48 000 000 000</a>
        </div>
      </section>

      <footer className="bf-footer">
        <div>zerogrid.pl · systemy off‑grid</div>
        <div>© 2025 · v2.4 demo</div>
      </footer>
    </main>
    </>
  );
}

function describeMode(sim, tweaks) {
  if (sim.mode === 'pv-mixed')
    return 'Panele pokrywają bieżący pobór, a nadwyżka trafia do magazynu — ładuje się na wieczór i noc.';
  if (sim.mode === 'pv-charging')
    return 'Panele wytwarzają nadwyżkę energii. Sterownik kieruje ją do magazynu.';
  if (sim.mode === 'pv-direct')
    return 'Cała energia z PV trafia bezpośrednio do budynku.';
  if (sim.mode === 'pv-plus-batt')
    return 'Słońce nie wystarcza na pełen pobór — magazyn dokłada brakującą moc do budynku w razie potrzeby.';
  if (sim.mode === 'gen-mixed')
    return 'Generator pokrywa bieżący pobór i jednocześnie ładuje magazyn. Wyłączy się automatycznie po osiągnięciu progu naładowania.';
  if (sim.mode === 'gen-charging')
    return 'Magazyn osiągnął minimalny próg nałądowania. Generator startuje automatycznie i ładuje baterię — uruchamia się tylko wtedy, gdy to konieczne.';
  if (sim.mode === 'gen-direct')
    return 'Generator pokrywa bieżący pobór. Po naładowaniu baterii zostanie automatycznie zatrzymany.';
  if (sim.mode === 'battery')
    return 'Budynek pracuje w pełnej autonomii — energia płynie wyłącznie z magazynu nałądowanego w ciągu dnia.';
  return 'System monitoruje warunki. Brak aktywnego zapotrzebowania na energię.';
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
