/* CardPulse — Site sections */

const { useTweaks } = window;

const APP_STORE_URL = "https://apps.apple.com/app/apple-store/id6754640005?pt=128186520&ct=from_product_hunt&mt=8";

const Logo = ({ size = 28 }) => (
  <div className="logo" style={{ height: size }}>
    <img src="assets/icon.png" alt="CardPulse" width={size} height={size} className="logo-mark" />
    <span className="logo-text">CardPulse</span>
  </div>
);

const AppStoreBadge = ({ size = "lg" }) => (
  <a href={APP_STORE_URL} target="_blank" rel="noopener noreferrer" className={`appstore-badge appstore-${size}`} aria-label="Download on the App Store">
    <svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" fill="currentColor">
      <path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/>
    </svg>
    <div className="appstore-text">
      <span className="appstore-pre">Download on the</span>
      <span className="appstore-store">App Store</span>
    </div>
  </a>
);

const Hero = () => (
  <section className="hero">
    <nav className="nav">
      <Logo />
      <div className="nav-right">
        <a href="#features" className="nav-link">Features</a>
        <a href="../assets/app/card-pulse/privacy-policy.html" className="nav-link">Privacy</a>
      </div>
    </nav>

    <div className="hero-grid">
      <div className="hero-copy">
        <h1 className="hero-headline">
          Always hit your <em>minimum spending.</em>
        </h1>
        <p className="hero-sub">
          Juggling four cards with four deadlines? CardPulse keeps every min-spend on track. It automatically track your tap-to-pay transactions, converts foreign currency, and surfaces insights — all without bank logins. Finally, a rewards tracker built for the way you actually spend.
        </p>
        <div className="hero-ctas">
          <AppStoreBadge size="lg" />
          <a href="#features" className="ghost-cta">See how it works ↓</a>
        </div>
      </div>

      <div className="hero-phone">
        <Phone />
      </div>
    </div>
  </section>
);

const FEATURES = [
  {
    label: "AUTO-TRACK",
    title: "Tap to pay. We do the rest.",
    body: "Pay through Apple Wallet and the transaction is automatically tracked. Nothing to type. (*requires one-time setup)",
    visual: "tap",
  },
  {
    label: "ONE SCREEN",
    title: "Every card. Every deadline. One look.",
    body: "Total min-spend, cards hit, cards behind, days left. The whole month at a glance.",
    visual: "ring",
  },
  {
    label: "ANALYSIS",
    title: "See where every dollar goes.",
    body: "Auto-categorized transactions across day, week, month, and year views.",
    visual: "donut",
  },
  {
    label: "GLOBAL",
    title: "Spending abroad? Already converted.",
    body: "Foreign currency gets pulled into your home currency so progress stays accurate.",
    visual: "fx",
  },
  {
    label: "PRIVATE",
    title: "No bank logins. Ever.",
    body: "We only read data from Apple Pay transactions. That's it.",
    visual: "lock",
  },
];

const TapScene = () => {
  const [phase, setPhase] = React.useState(0);
  // 0: terminal waiting, phone hidden
  // 1: phone slides up
  // 2: terminal green check
  // 3: phone shows notification

  React.useEffect(() => {
    const CYCLE = 5600;
    let timers = [];
    const run = () => {
      setPhase(0);
      timers.push(setTimeout(() => setPhase(1), 700));
      timers.push(setTimeout(() => setPhase(2), 2100));
      timers.push(setTimeout(() => setPhase(3), 2900));
    };
    run();
    const id = setInterval(() => {
      timers.splice(0).forEach(clearTimeout);
      run();
    }, CYCLE);
    return () => { timers.splice(0).forEach(clearTimeout); clearInterval(id); };
  }, []);

  return (
    <div className="fv-tap">
      {/* Terminal reader — large, centered */}
      <div className={`fv-term ${phase >= 2 ? "fv-term-ok" : ""}`}>
        <div className="fv-term-screen">
          <div className="fv-term-idle">
            <svg viewBox="0 0 24 20" width="28" height="23" fill="none" aria-hidden="true">
              <circle cx="12" cy="16" r="2" fill="white" opacity="0.9"/>
              <path d="M7.5 12 a6.5 6.5 0 0 1 9 0" stroke="white" strokeWidth="1.6" strokeLinecap="round" opacity="0.7"/>
              <path d="M4 7.5 a11 11 0 0 1 16 0" stroke="white" strokeWidth="1.6" strokeLinecap="round" opacity="0.35"/>
            </svg>
            <div className="fv-term-amount">S$15.60</div>
            <div className="fv-term-hint">Tap to pay</div>
          </div>
          <div className="fv-term-check">
            <svg viewBox="0 0 40 40" width="44" height="44" fill="none" aria-hidden="true">
              <circle cx="20" cy="20" r="18" fill="#22c55e"/>
              <path d="M11 20.5l6.5 6.5 11.5-12" stroke="white" strokeWidth="2.8" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
            <div className="fv-term-approved">Approved</div>
          </div>
        </div>
        <div className="fv-term-slot">
          <span className="fv-term-slot-label">CARD</span>
          <div className="fv-term-slot-line" />
        </div>
        <div className="fv-term-keypad">
          {Array.from({ length: 12 }).map((_, i) => (
            <div key={i} className={`fv-term-key fv-term-key-${i}`} />
          ))}
        </div>
      </div>

      {/* Phone — slides up from below */}
      <div className={`fv-miniphone ${phase >= 1 ? "fv-miniphone-up" : ""}`}>
        <div className="fv-miniphone-btn fv-miniphone-vol1" />
        <div className="fv-miniphone-btn fv-miniphone-vol2" />
        <div className="fv-miniphone-btn fv-miniphone-power" />
        <div className="fv-miniphone-screen">
          <div className="fv-miniphone-bar">
            <span className="fv-miniphone-time">9:41</span>
            <div className="fv-miniphone-island" />
            <div className="fv-miniphone-batt" />
          </div>
          <div className={`fv-miniphone-toast ${phase >= 3 ? "fv-miniphone-toast-show" : ""}`}>
            <div className="fv-miniphone-toast-dot" />
            <div>
              <div className="fv-miniphone-toast-title">Transaction added</div>
              <div className="fv-miniphone-toast-sub">KFC · S$15.60 → HSBC Live+</div>
            </div>
          </div>
          <div className="fv-ap-screen">
            <div className="fv-ap-header">
              <svg viewBox="0 0 24 24" width="16" height="16" fill="white" aria-hidden="true">
                <path d="M17.05 20.28c-.98.95-2.05.8-3.08.35-1.09-.46-2.09-.48-3.24 0-1.44.62-2.2.44-3.06-.35C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/>
              </svg>
              <span className="fv-ap-header-label">Apple Pay</span>
            </div>
            <div className="fv-ap-card">
              <div className="fv-ap-card-top">
                <span className="fv-ap-card-name">HSBC Live+</span>
                <svg width="36" height="12" viewBox="0 0 72 24" aria-hidden="true">
                  <text x="0" y="20" fontFamily="Arial, Helvetica, sans-serif" fontWeight="900" fontSize="24" fontStyle="italic" fill="white" letterSpacing="1">VISA</text>
                </svg>
              </div>
              <div className="fv-ap-card-num">•••• •••• •••• 4242</div>
            </div>
            <div className="fv-ap-hold">
              <svg viewBox="0 0 24 20" width="20" height="17" fill="none" aria-hidden="true">
                <circle cx="12" cy="16" r="2" fill="white" opacity="0.9"/>
                <path d="M7.5 12 a6.5 6.5 0 0 1 9 0" stroke="white" strokeWidth="1.6" strokeLinecap="round" opacity="0.7"/>
                <path d="M4 7.5 a11 11 0 0 1 16 0" stroke="white" strokeWidth="1.6" strokeLinecap="round" opacity="0.4"/>
              </svg>
              <span>Hold near reader</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

const RingVisual = () => {
  const [progress, setProgress] = React.useState(0);
  const R = 38;
  const C = 2 * Math.PI * R;

  React.useEffect(() => {
    let raf;
    const start = performance.now();
    const animate = (now) => {
      const elapsed = (now - start) / 1000;
      const target = 0.44;
      const eased = Math.min(1, elapsed / 1.6);
      const e = 1 - Math.pow(1 - eased, 3);
      const breath = 0.005 * Math.sin(elapsed * 1.4);
      setProgress(target * e + (eased >= 1 ? breath : 0));
      raf = requestAnimationFrame(animate);
    };
    raf = requestAnimationFrame(animate);
    return () => cancelAnimationFrame(raf);
  }, []);

  const dash = C * progress;

  return (
    <div className="fv-minspend">
      <div className="fv-minspend-left">
        <div className="fv-ms-label">MIN-SPEND TARGET · APRIL</div>
        <div className="fv-ms-amount">S$1,900</div>
        <div className="fv-ms-meta">
          <div className="fv-ms-col">
            <div className="fv-ms-meta-label">CARDS HIT</div>
            <div className="fv-ms-meta-val"><span className="fv-ms-strong">2</span><span className="fv-ms-faint">/3</span></div>
          </div>
          <div className="fv-ms-col">
            <div className="fv-ms-meta-label">NEXT DEADLINE</div>
            <div className="fv-ms-meta-val fv-ms-orange">4d</div>
          </div>
        </div>
        <div className="fv-ms-foot">S$1,064 left to hit target</div>
      </div>
      <div className="fv-minspend-right">
        <svg viewBox="0 0 100 100" width="118" height="118">
          <circle cx="50" cy="50" r={R} fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth="9"/>
          <circle
            cx="50" cy="50" r={R}
            fill="none"
            stroke="url(#fv-ms-grad)"
            strokeWidth="9"
            strokeLinecap="round"
            strokeDasharray={`${dash} ${C}`}
            transform="rotate(-90 50 50)"
          />
          <defs>
            <linearGradient id="fv-ms-grad" x1="0" y1="0" x2="1" y2="1">
              <stop offset="0%" stopColor="#7AA8FF"/>
              <stop offset="100%" stopColor="#4F6BFF"/>
            </linearGradient>
          </defs>
        </svg>
        <div className="fv-ms-ring-center">S$1,064</div>
      </div>
    </div>
  );
};

const FeatureVisual = ({ kind }) => {
  if (kind === "ring") {
    return <RingVisual />;
  }
  if (kind === "tap") return <TapScene />;
  if (kind === "fx") {
    return (
      <div className="fv-fx">
        <div className="fv-fx-row"><span>$98.00</span><span className="fv-fx-tag">USD</span></div>
        <div className="fv-fx-arrow">↓</div>
        <div className="fv-fx-row fv-fx-row-out"><span>S$132.40</span><span className="fv-fx-tag fv-fx-tag-out">SGD</span></div>
      </div>
    );
  }
  if (kind === "donut") {
    const total = 1961;
    const segments = [
      { value: 962, color: "#FF8A3D", name: "Food & Drinks", amount: "S$962" },
      { value: 456, color: "#FF4D6D", name: "Health", amount: "S$456" },
      { value: 170, color: "#D64ACD", name: "Shopping", amount: "S$170" },
      { value: 147, color: "#22C7D8", name: "Other", amount: "S$147" },
      { value: 126, color: "#E944B5", name: "Groceries", amount: "S$126" },
      { value: 100, color: "#3E76FF", name: "Sports", amount: "S$100" },
    ];
    let cumulative = 0;
    const R = 40;
    const C = 2 * Math.PI * R;
    return (
      <div className="fv-analysis">
        <div className="fv-an-total">
          <div className="fv-an-total-label">TOTAL SPEND</div>
          <div className="fv-an-total-amount">S$2,035.36</div>
          <div className="fv-an-total-delta">↓ 61% vs March</div>
        </div>
        <div className="fv-an-donut-card">
          <div className="fv-an-donut-ring">
            <svg viewBox="0 0 100 100" width="92" height="92" aria-hidden="true">
              <circle cx="50" cy="50" r={R} fill="none" stroke="rgba(255,255,255,0.06)" strokeWidth="16" />
              {segments.map((s, i) => {
                const len = i === segments.length - 1 ? C - cumulative : (s.value / total) * C;
                const offset = -cumulative;
                cumulative += len;
                return (
                  <circle
                    key={i}
                    cx="50"
                    cy="50"
                    r={R}
                    fill="none"
                    stroke={s.color}
                    strokeWidth="16"
                    strokeDasharray={`${len} ${C - len}`}
                    strokeDashoffset={offset}
                    transform="rotate(-90 50 50)"
                  />
                );
              })}
            </svg>
          </div>
          <div className="fv-an-legend">
            {segments.map((s) => (
              <div className="fv-an-row" key={s.name}>
                <span className="fv-an-dot" style={{ background: s.color }}></span>
                <span className="fv-an-name">{s.name}</span>
                <span className="fv-an-amt">{s.amount}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }
  if (kind === "lock") {
    return (
      <div className="fv-lock">
        <div className="fv-lock-phone">
          <div className="fv-lock-btn fv-lock-vol1" />
          <div className="fv-lock-btn fv-lock-vol2" />
          <div className="fv-lock-btn fv-lock-power" />
          <div className="fv-lock-screen">
            <div className="fv-lock-island" />
            <div className="fv-lock-url-bar">
              <svg width="7" height="8" viewBox="0 0 8 10" fill="none" aria-hidden="true">
                <rect x="1" y="4" width="6" height="6" rx="1" fill="#999"/>
                <path d="M2.5 4V3a1.5 1.5 0 0 1 3 0v1" stroke="#999" strokeWidth="1" strokeLinecap="round"/>
              </svg>
              <span className="fv-lock-url-text">mybank.com</span>
            </div>
            <div className="fv-lock-form">
              <div className="fv-lock-bank-header">MY BANK</div>
              <div className="fv-lock-field-label">Username</div>
              <div className="fv-lock-field" />
              <div className="fv-lock-field-label">Password</div>
              <div className="fv-lock-field fv-lock-field-pw">● ● ● ●</div>
              <div className="fv-lock-submit">Log In</div>
            </div>
          </div>
        </div>
        <svg className="fv-lock-ban" viewBox="0 0 240 240" aria-hidden="true">
          <circle cx="120" cy="120" r="108" fill="none" stroke="var(--accent)" strokeWidth="13" strokeOpacity="0.9"/>
          <line x1="44" y1="44" x2="196" y2="196" stroke="var(--accent)" strokeWidth="13" strokeLinecap="round" strokeOpacity="0.9"/>
        </svg>
      </div>
    );
  }
  if (kind === "csv") {
    return (
      <div className="fv-csv">
        <div className="fv-csv-row fv-csv-head"><span>Date</span><span>Card</span><span>Amount</span></div>
        <div className="fv-csv-row"><span>04-12</span><span>UOB Lady's</span><span>−105.00</span></div>
        <div className="fv-csv-row"><span>04-13</span><span>Citi Cash</span><span>−59.85</span></div>
        <div className="fv-csv-row"><span>04-14</span><span>HSBC Live+</span><span>−15.60</span></div>
      </div>
    );
  }
  return null;
};

const Features = () => (
  <section className="features" id="features">
    <div className="features-head">
      <div className="section-eyebrow">FEATURES</div>
      <h2 className="section-title">Built by someone who <em>uses</em> lots of cards.</h2>
    </div>
    <div className="feature-grid">
      {FEATURES.map((f, i) => (
        <div className={`feature-card feature-card-${i}`} key={f.label}>
          <div className="feature-visual">
            <FeatureVisual kind={f.visual} />
          </div>
          <div className="feature-body">
            <div className="feature-label">{f.label}</div>
            <div className="feature-title">{f.title}</div>
            <div className="feature-text">{f.body}</div>
          </div>
        </div>
      ))}
    </div>
  </section>
);

const FinalCTA = () => (
  <section className="final">
    <h2 className="final-title">
      Stop missing rewards <br className="br-mobile"/>
      you should earn.
    </h2>
    <p className="final-sub">Free to download. iOS only. Apple Wallet required.</p>
    <AppStoreBadge size="lg" />
  </section>
);

const Footer = () => (
  <footer className="footer">
    <div className="footer-inner">
      <Logo size={22} />
      <div className="footer-meta">
        <a href="../assets/app/card-pulse/privacy-policy.html">Privacy</a>
      </div>
      <div className="footer-copy">© 2026 Zhang Qichuan. Built in Singapore.</div>
    </div>
  </footer>
);

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "dark"
}/*EDITMODE-END*/;

const App = () => {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);

  React.useEffect(() => {
    document.documentElement.setAttribute("data-theme", tweaks.theme);
  }, [tweaks.theme]);

  return (
    <div className="page" data-theme={tweaks.theme}>
      <Hero />
      <Features />
      <FinalCTA />
      <Footer />

      <window.TweaksPanel title="Tweaks">
        <window.TweakSection title="Theme">
          <window.TweakRadio
            value={tweaks.theme}
            onChange={(v) => setTweak("theme", v)}
            options={[
              { value: "lavender", label: "Lavender" },
              { value: "dark", label: "Dark" },
              { value: "editorial", label: "Editorial" },
            ]}
          />
        </window.TweakSection>
      </window.TweaksPanel>
    </div>
  );
};

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