/* italicense — main app */
const { useState, useEffect, useMemo, useRef } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "Babyblue · cream",
  "displayFont": "Instrument Serif",
  "showTicker": true
}/*EDITMODE-END*/;

const PALETTES = {
  "Babyblue · cream": ["#f4f1ea", "#15202b", "#2d6a9f", "#b9d8ee"],
  "Powder · ink":    ["#eef3f7", "#14202b", "#3a78a8", "#a5c8e1"],
  "Mist · stone":    ["#ecedeb", "#1b242c", "#4a7da3", "#cbdae6"],
  "Sky · midnight":  ["#e4eef7", "#0d1822", "#1e5688", "#86b3d6"]
};

const DISPLAY_FONTS = {
  "Instrument Serif": "'Instrument Serif', 'Times New Roman', serif",
  "Newsreader":       "'Newsreader', 'Times New Roman', serif",
  "EB Garamond":      "'EB Garamond', 'Times New Roman', serif"
};

// ----- small helpers -----
function Compass() {
  return <span className="compass" aria-hidden="true"></span>;
}

function mix(a, b, t) {
  // hex mix
  const pa = parseHex(a), pb = parseHex(b);
  const r = Math.round(pa[0] + (pb[0] - pa[0]) * t);
  const g = Math.round(pa[1] + (pb[1] - pa[1]) * t);
  const bl = Math.round(pa[2] + (pb[2] - pa[2]) * t);
  return `rgb(${r}, ${g}, ${bl})`;
}
function parseHex(h) {
  const s = h.replace("#", "");
  return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)];
}

function NavBar({ onNav, currentSection }) {
  return (
    <header className="nav">
      <div className="nav-inner">
        <div className="nav-left">
          <a className={"nav-link" + (currentSection === "guides" ? " active" : "")} onClick={() => onNav("guides")}>Guides</a>
          <a className={"nav-link" + (currentSection === "permit" ? " active" : "")} onClick={() => onNav("permit")}>The Permit</a>
          <a className={"nav-link" + (currentSection === "about" ? " active" : "")} onClick={() => onNav("about")}>Editorial</a>
          <a className="nav-link" onClick={() => onNav("guides")}>Atlas</a>
        </div>
        <a className="logo" onClick={() => onNav("top")}>itali<em>cense</em><span className="dot">.</span></a>
        <div className="nav-right">
          <span className="nav-meta">Vol. IV · MMXXVI</span>
          <a className="nav-link" onClick={() => onNav("permit")}>Apply →</a>
        </div>
      </div>
    </header>
  );
}

function Masthead({ onNav, showTicker }) {
  return (
    <div className="masthead" data-screen-label="01 Hero">
      <div className="masthead-top">
        <span className="vol">Issue 04 · Spring &amp; Summer · 2026</span>
        <span className="date">Established somewhere on the road</span>
      </div>
      <div className="hero">
        <div>
          <span className="hero-kicker"><Compass />Driving guides around the world</span>
          <h1>
            How to drive<br />
            a country you<br />
            <em>have never</em> driven.
          </h1>
          <p className="hero-sub">
            Ten places. The rules that matter, the rules that don't, and the routes locals would take if they had a guest in the passenger seat.
          </p>
        </div>
        <aside className="hero-aside">
          <p>
            <strong>italicense</strong> is a quiet publication for travellers who would rather drive themselves — through Tuscan vineyards, Japanese expressways, Icelandic fog — and arrive understanding the road.
          </p>
          <p>
            Each guide is written by someone who lives there. Each is checked against the law that applies the week we publish it. Each tells you what the rental-car counter won't.
          </p>
          <a className="cta" onClick={() => onNav("guides")}>Begin with the guides ↓</a>
        </aside>
      </div>
      <Ticker />
      {!showTicker && <style>{`.hero-ticker { display: none; }`}</style>}
    </div>
  );
}

function Ticker() {
  const items = [
    "ITALY · ZTL fines arrive six months later",
    "JAPAN · phone-number nav",
    "ICELAND · the door is the claim",
    "NEW ZEALAND · passing lanes matter",
    "MOROCCO · get the receipt",
    "NORWAY · cameras are patient",
    "SCOTLAND · single-track manners",
    "MEXICO · take the cuota",
    "PORTUGAL · don't drive Lisbon",
    "SOUTH AFRICA · the four-way is sacred"
  ];
  const line = items.map((t, i) => (
    <React.Fragment key={i}>
      <span>{t}</span><span className="sep">◇</span>
    </React.Fragment>
  ));
  return (
    <div className="hero-ticker">
      <div className="hero-ticker-track">
        <span>{line}</span><span>{line}</span>
      </div>
    </div>
  );
}

// ----- guide card -----
function GuideCover({ guide, size = "card" }) {
  return (
    <div className={"guide-cover " + (guide.coverHue || "") + (guide.image ? " has-image" : "")}>
      {guide.image
        ? <img className="cover-photo" src={guide.image} alt={guide.country + " — " + guide.cover} loading="lazy" />
        : <div className="placeholder-stripes"></div>}
      <div className="country-mark">{guide.country}</div>
      <div className="cover-num">{guide.issue}</div>
      <div className="cover-caption">{guide.cover}</div>
    </div>
  );
}

function GuideCard({ guide, variant, onOpen }) {
  return (
    <article className={"guide-card " + (variant || "")} onClick={() => onOpen(guide.id)}>
      <div className="guide-card-head">
        <span className="issue">{guide.issue} · {guide.readTime}</span>
        <span className="region">{guide.region}</span>
      </div>
      <GuideCover guide={guide} />
      <div className="country-line">{guide.country}</div>
      <h3>{guide.headline}</h3>
      <p className="excerpt">{guide.excerpt}</p>
      <div className="byline">
        <span>By {guide.drivenBy}</span>
        <span>{guide.dateline.split("·")[1] && guide.dateline.split("·")[1].trim()}</span>
      </div>
    </article>
  );
}

// ----- filter & grid -----
function GuidesSection({ onOpen }) {
  const [filter, setFilter] = useState("All");
  const regions = useMemo(() => {
    const r = new Set(GUIDES.map(g => g.region));
    return ["All", ...Array.from(r)];
  }, []);
  const filtered = filter === "All" ? GUIDES : GUIDES.filter(g => g.region === filter);

  // give variant pattern: every 7 cards => featured & wide accents
  const layout = (i) => {
    if (i === 0) return "featured";
    if (i === 5) return "featured";
    return "";
  };

  return (
    <section className="section" id="guides" data-screen-label="02 Guides">
      <div className="section-head">
        <span className="num">10</span>
        <h2>The Guides</h2>
        <span className="meta">Filed from {GUIDES.length} countries</span>
      </div>
      <div className="filter-bar">
        {regions.map(r => (
          <button key={r}
            className={"filter-chip" + (filter === r ? " active" : "")}
            onClick={() => setFilter(r)}>
            {r}
          </button>
        ))}
      </div>
      <div className="guides-grid">
        {filtered.map((g, i) => (
          <GuideCard key={g.id} guide={g} variant={filter === "All" ? layout(i) : ""} onOpen={onOpen} />
        ))}
      </div>
    </section>
  );
}

// ----- reader -----
function Reader({ guideId, onClose, onOpen }) {
  const guide = GUIDES.find(g => g.id === guideId);
  const scrollRef = useRef(null);
  const [progress, setProgress] = useState(0);

  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = 0;
    function onKey(e) { if (e.key === "Escape") onClose(); }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [guideId]);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    function onScroll() {
      const t = el.scrollTop;
      const h = el.scrollHeight - el.clientHeight;
      setProgress(Math.max(0, Math.min(1, t / h)));
    }
    el.addEventListener("scroll", onScroll);
    return () => el.removeEventListener("scroll", onScroll);
  }, [guideId]);

  if (!guide) return null;
  const idx = GUIDES.findIndex(g => g.id === guideId);
  const next = GUIDES[(idx + 1) % GUIDES.length];
  const prev = GUIDES[(idx - 1 + GUIDES.length) % GUIDES.length];

  // progress dots — 10 dots, fill based on which guide we're on; for inside-reading we'll fill based on scroll progress
  const dotsOn = Math.ceil(progress * 10);

  return (
    <div className="reader" ref={scrollRef} data-screen-label={"Reader · " + guide.country}>
      <div className="reader-nav">
        <div className="reader-nav-inner">
          <button className="reader-close" onClick={onClose}>← All guides</button>
          <div className="reader-progress">
            {Array.from({ length: 10 }).map((_, i) =>
              <span key={i} className={"dot" + (i < dotsOn ? " on" : "")}></span>
            )}
          </div>
          <span className="reader-close">{guide.issue} of 10</span>
        </div>
      </div>

      <div className="reader-masthead">
        <div className="reader-issue">
          <span>{guide.issue} · {guide.region} · {guide.readTime} read</span>
          <span>{guide.dateline}</span>
        </div>
        <h1 className="reader-country">
          {guide.country.split(" ").map((w, i) => i === guide.country.split(" ").length - 1 ? <em key={i}>{w}</em> : <span key={i}>{w} </span>)}
        </h1>
        <p className="reader-headline">{guide.headline}</p>
        <div className="reader-byline">
          <span>By {guide.drivenBy}</span>
          <span>Filed {guide.dateline.split("·")[1] && guide.dateline.split("·")[1].trim()}</span>
        </div>
      </div>

      <div className="reader-cover">
        <div className={"reader-cover-inner " + (guide.coverHue || "") + (guide.image ? " has-image" : "")}>
          {guide.image
            ? <img className="cover-photo" src={guide.image} alt={guide.country + " — " + guide.cover} />
            : <div className="placeholder-stripes"></div>}
          <span className="caption">{guide.cover}</span>
        </div>
      </div>

      <div className="reader-meta-bar">
        <div className="cell"><div className="label">Side</div><div className="value">{guide.bySide}</div></div>
        <div className="cell"><div className="label">Limit</div><div className="value">{guide.speed}</div></div>
        <div className="cell"><div className="label">BAC</div><div className="value">{guide.bac}</div></div>
        <div className="cell"><div className="label">Permit</div><div className="value">{guide.idp}</div></div>
        <div className="cell"><div className="label">Fuel</div><div className="value">{guide.fuel}</div></div>
      </div>

      <div className="reader-body">
        {guide.sections.map((sec, i) => <Block key={i} sec={sec} />)}
      </div>

      <div className="reader-foot">
        <div className="next-card" onClick={() => onOpen(prev.id)}>
          <div>
            <div className="label">← Previous</div>
            <h4 className="country">{prev.country}</h4>
            <div className="hl">{prev.headline}</div>
          </div>
        </div>
        <div className="next-card right" onClick={() => onOpen(next.id)}>
          <div>
            <div className="label">Next →</div>
            <h4 className="country">{next.country}</h4>
            <div className="hl">{next.headline}</div>
          </div>
        </div>
      </div>
    </div>
  );
}

function Block({ sec }) {
  if (sec.kind === "lede") {
    return (
      <div className="col">
        <div className="section-block lede">
          <p>{sec.body}</p>
        </div>
      </div>
    );
  }
  if (sec.kind === "prose") {
    return (
      <div className="col">
        <div className="section-block">
          {sec.title && <div className="label"><Compass />{sec.title}</div>}
          <p>{sec.body}</p>
        </div>
      </div>
    );
  }
  if (sec.kind === "pull") {
    return (
      <div className="full">
        <blockquote className="pull-quote">{sec.text}</blockquote>
      </div>
    );
  }
  if (sec.kind === "rules") {
    return (
      <div className="full">
        <div className="section-block">
          <div className="label"><Compass />{sec.title}</div>
          <div className="rules-table">
            {sec.items.map(([k, v], i) => (
              <div className="row" key={i}>
                <div className="key">{k}</div>
                <div className="val">{v}</div>
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  }
  if (sec.kind === "routes") {
    return (
      <div className="full">
        <div className="section-block">
          <div className="label"><Compass />{sec.title}</div>
          <div className="routes-grid">
            {sec.items.map((r, i) => (
              <article className="route-card" key={i}>
                <div className="num">{String(i + 1).padStart(2, "0")}</div>
                <div className="from-to">
                  <span>{r.from}</span><span className="arrow">→</span><span>{r.to}</span>
                  <span className="hours">{r.hours} h</span>
                </div>
                <h3 className="name">{r.name}</h3>
                <p className="note">{r.note}</p>
              </article>
            ))}
          </div>
        </div>
      </div>
    );
  }
  if (sec.kind === "warning") {
    return (
      <div className="full">
        <div className="warning-block">
          <div className="label">{sec.title || "Don't"}</div>
          <ul>
            {sec.items.map((it, i) => <li key={i}>{it}</li>)}
          </ul>
        </div>
      </div>
    );
  }
  return null;
}

// ----- permit / about / newsletter / footer -----
function PermitSection({ onNav }) {
  return (
    <section className="section tinted" id="permit" data-screen-label="03 The Permit">
      <div className="inner">
        <div className="section-head">
          <span className="num">A</span>
          <h2>The Permit</h2>
          <span className="meta">For countries that want one in writing</span>
        </div>
        <div className="about-grid">
          <div>
            <span className="lede-mark">On the document itself</span>
            <h3>An International Driving Permit is a translation, not a licence.</h3>
            <p>
              It exists because your home licence is in one language and the police officer in front of you reads another. The permit translates the data — your name, your categories, your photo — into the seven working languages of the 1949 Geneva and 1968 Vienna conventions, and stamps it with the seal of the issuing country's automobile association.
            </p>
            <p>
              You carry it alongside your domestic licence. It is valid for one year. It does not give you the right to drive — your home licence does that — and it does not extend your validity if you are disqualified at home. Some countries (Japan, most notably) accept only the 1949 version. Some (most of mainland Europe) prefer 1968. A small handful of countries accept neither and require a local conversion.
            </p>
            <p>
              We issue both conventions. We courier in 48 hours to most destinations. We don't pretend to do anything more than translate a document, accurately, on time.
            </p>
          </div>
          <div className="idp-card">
            <div className="seal">
              <span className="num">№</span>
              <span className="tag">Authorised<br />issuer</span>
            </div>
            <h4>1949 &amp; 1968 conventions</h4>
            <p>One application. Both permits issued where eligible. Plastic-card format, photograph held to international photo-ID standards, valid one year from issue.</p>
            <div className="price">$24<span className="unit">/ permit · all-in</span></div>
            <p style={{ fontSize: 12, color: "var(--ink-3)" }}>Courier from $9 · ten countries supported · refunded if rejected at border.</p>
            <button className="start-btn" onClick={() => alert("Application flow would open here. This is a design preview.")}>Begin application →</button>
          </div>
        </div>
      </div>
    </section>
  );
}

function EditorialSection() {
  return (
    <section className="section" id="about" data-screen-label="04 Editorial">
      <div className="section-head">
        <span className="num">B</span>
        <h2>The Editorial</h2>
        <span className="meta">How the guides get made</span>
      </div>
      <div className="about-grid">
        <div>
          <span className="lede-mark">Editor's note</span>
          <h3>We don't publish a guide until someone we trust has driven the route in the last twelve months.</h3>
          <p>
            Travel writing has an honesty problem. Rental-car pages copy each other. Forum posts age into wrong. The country changes — a new toll system, a new alcohol limit, a new road across a fjord — and the article you're reading was last edited in 2019.
          </p>
          <p>
            italicense pays a small panel of resident drivers — taxi veterans, ex-rally drivers, long-haul couriers, the friends of friends who know the back roads of their region — to walk us through every fine, gesture, and unsaid rule. We update each guide annually. We mark the month it was last verified at the top of the page.
          </p>
          <p>
            We do not run advertising. We earn from the permits. That keeps the guides honest.
          </p>
        </div>
        <div>
          <div style={{ borderTop: "1px solid var(--ink)", paddingTop: 18, marginBottom: 32 }}>
            <div className="mono" style={{ color: "var(--ink-3)", marginBottom: 14 }}>Currently verified</div>
            {[
              ["Italy", "Apr 2026"],
              ["Japan", "Mar 2026"],
              ["Iceland", "Feb 2026"],
              ["New Zealand", "Jan 2026"],
              ["Morocco", "Apr 2026"],
              ["Norway", "Mar 2026"],
              ["Scotland", "Feb 2026"],
              ["Mexico", "Jan 2026"],
              ["Portugal", "Mar 2026"],
              ["South Africa", "Feb 2026"]
            ].map(([c, d]) => (
              <div key={c} style={{
                display: "flex", justifyContent: "space-between",
                padding: "10px 0", borderBottom: "1px solid var(--rule)",
                fontSize: 15
              }}>
                <span style={{ fontFamily: "'Instrument Serif', serif", fontSize: 20 }}>{c}</span>
                <span className="mono" style={{ color: "var(--ink-3)" }}>{d}</span>
              </div>
            ))}
          </div>
          <p style={{ fontSize: 14, color: "var(--ink-3)", fontStyle: "italic", fontFamily: "'Instrument Serif', serif" }}>
            Forty additional countries are in the queue. We'd rather publish ten right than fifty rough.
          </p>
        </div>
      </div>
    </section>
  );
}

function Newsletter() {
  const [sent, setSent] = useState(false);
  return (
    <section className="newsletter" data-screen-label="05 Newsletter">
      <div className="newsletter-inner">
        <h2>One letter, <em>every other Friday</em>, from somewhere on a road.</h2>
        <p>A short dispatch with a new guide, a change in a country's road law, or a route worth a detour. No ads. Easy to leave.</p>
        {!sent ? (
          <form className="newsletter-form" onSubmit={(e) => { e.preventDefault(); setSent(true); }}>
            <input type="email" placeholder="your@email" required />
            <button type="submit">Subscribe</button>
          </form>
        ) : (
          <div className="newsletter-form" style={{ justifyContent: "center", padding: "14px 18px" }}>
            <span className="mono" style={{ color: "var(--baby)" }}>✓ Thanks — first dispatch is on its way.</span>
          </div>
        )}
        <div className="newsletter-meta">No tracking. No partners. Plain text.</div>
      </div>
    </section>
  );
}

function Footer() {
  return (
    <footer data-screen-label="06 Footer">
      <div className="footer-inner">
        <div className="col brand">
          <a className="logo">itali<em>cense</em><span className="dot">.</span></a>
          <p>Driving guides around the world, and the permits that go with them. Independent, advertising-free, written by residents.</p>
        </div>
        <div className="col">
          <h5>Guides</h5>
          <ul>
            {GUIDES.slice(0, 5).map(g => <li key={g.id}>{g.country}</li>)}
          </ul>
        </div>
        <div className="col">
          <h5>More</h5>
          <ul>
            {GUIDES.slice(5).map(g => <li key={g.id}>{g.country}</li>)}
          </ul>
        </div>
        <div className="col">
          <h5>Office</h5>
          <ul>
            <li>The Permit</li>
            <li>Editorial</li>
            <li>Press</li>
            <li>hello@italicense.com</li>
          </ul>
        </div>
      </div>
      <div className="footer-meta">
        <span>© MMXXVI italicense · Vol. IV</span>
        <span>Hand-made on the road</span>
      </div>
    </footer>
  );
}

// ----- top-level app -----
function App() {
  const [reading, setReading] = useState(null);
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  // Apply palette to CSS variables
  useEffect(() => {
    const [paper, ink, sea, baby] = PALETTES[t.palette] || PALETTES["Babyblue · cream"];
    const root = document.documentElement;
    root.style.setProperty("--paper", paper);
    root.style.setProperty("--ink", ink);
    root.style.setProperty("--sea", sea);
    root.style.setProperty("--baby", baby);
    // derived
    root.style.setProperty("--baby-3", mix(paper, baby, 0.45));
    root.style.setProperty("--baby-2", mix(baby, sea, 0.35));
    root.style.setProperty("--paper-2", mix(paper, baby, 0.18));
    root.style.setProperty("--rule", mix(paper, ink, 0.12));
    root.style.setProperty("--rule-2", mix(paper, ink, 0.22));
    root.style.setProperty("--ink-2", mix(ink, paper, 0.30));
    root.style.setProperty("--ink-3", mix(ink, paper, 0.55));
  }, [t.palette]);

  useEffect(() => {
    const stack = DISPLAY_FONTS[t.displayFont] || DISPLAY_FONTS["Instrument Serif"];
    // override the .serif font family via CSS variable
    document.documentElement.style.setProperty("--display-font", stack);
    // patch live rules
    const style = document.getElementById("__display-font-override") || (() => {
      const s = document.createElement("style"); s.id = "__display-font-override";
      document.head.appendChild(s); return s;
    })();
    style.textContent = `.serif, h1, h2, h3, h4, .reader-country, .pull-quote, .route-card .name, .next-card .country, .reader-headline, .logo, .hero-sub, .idp-card h4, .about-grid h3, .newsletter h2, .hero h1, .section-head h2, .reader-cover-inner em, .guide-card h3 { font-family: ${stack}; }`;
  }, [t.displayFont]);

  function handleNav(target) {
    if (target === "top") {
      window.scrollTo({ top: 0, behavior: "smooth" });
      return;
    }
    const el = document.getElementById(target);
    if (el) {
      const top = el.getBoundingClientRect().top + window.scrollY - 60;
      window.scrollTo({ top, behavior: "smooth" });
    }
  }

  // disable body scroll while reading
  useEffect(() => {
    document.body.style.overflow = reading ? "hidden" : "";
    return () => { document.body.style.overflow = ""; };
  }, [reading]);

  return (
    <>
      <NavBar onNav={handleNav} currentSection="" />
      <Masthead onNav={handleNav} showTicker={t.showTicker} />
      <GuidesSection onOpen={setReading} />
      <PermitSection onNav={handleNav} />
      <EditorialSection />
      <Newsletter />
      <Footer />
      {reading && (
        <Reader
          guideId={reading}
          onClose={() => setReading(null)}
          onOpen={(id) => setReading(id)}
        />
      )}
      <TweaksPanel>
        <TweakSection label="Palette" />
        <TweakSelect label="Scheme" value={t.palette}
          options={Object.keys(PALETTES)}
          onChange={(v) => setTweak('palette', v)} />
        <TweakSection label="Typography" />
        <TweakSelect label="Display face" value={t.displayFont}
          options={Object.keys(DISPLAY_FONTS)}
          onChange={(v) => setTweak('displayFont', v)} />
        <TweakSection label="Masthead" />
        <TweakToggle label="Show news ticker" value={t.showTicker}
          onChange={(v) => setTweak('showTicker', v)} />
      </TweaksPanel>
    </>
  );
}

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