// === Liburan Keluarga — Sidoarjo ↔ Batu, 1–2 Mei 2026 ===
const { useState, useEffect, useRef, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "terracotta",
  "compactCards": false
}/*EDITMODE-END*/;

const ACCENTS = {
  terracotta: { c: "#C25B3F", name: "Terakota" },
  moss:       { c: "#6B8E5A", name: "Lumut" },
  ink:        { c: "#1F2D24", name: "Tinta" },
  saffron:    { c: "#C8893A", name: "Safron" },
};

// ---------- Tiny atoms ----------
const Mono = ({ children, style }) => (
  <span style={{ fontFamily: "'JetBrains Mono', ui-monospace, monospace", fontSize: 10.5, letterSpacing: 0.4, textTransform: "uppercase", ...style }}>{children}</span>
);

const Placeholder = ({ label, h = 140, tone = "warm" }) => {
  const bg = tone === "warm"
    ? "repeating-linear-gradient(135deg, #E8DFCE 0 8px, #DFD3BC 8px 16px)"
    : "repeating-linear-gradient(135deg, #2A3B30 0 8px, #243329 8px 16px)";
  const fg = tone === "warm" ? "#5C5443" : "#C9D5C2";
  return (
    <div style={{
      width: "100%", height: h, borderRadius: 14, background: bg,
      display: "flex", alignItems: "center", justifyContent: "center",
      color: fg, position: "relative", overflow: "hidden",
    }}>
      <Mono style={{ color: fg, opacity: 0.85 }}>{label}</Mono>
    </div>
  );
};

const Pill = ({ children, color = "#1F2D24", bg = "rgba(31,45,36,0.06)" }) => (
  <span style={{
    display: "inline-flex", alignItems: "center", gap: 4,
    padding: "3px 8px", borderRadius: 999, background: bg, color,
    fontFamily: "'JetBrains Mono', ui-monospace, monospace",
    fontSize: 9.5, letterSpacing: 0.5, textTransform: "uppercase",
    border: "1px solid rgba(31,45,36,0.08)",
  }}>{children}</span>
);

// ---------- DATA (strictly from the brief) ----------
const TRIP = {
  title: "Liburan Keluarga",
  subtitle: "Sidoarjo → Batu → Pakis",
  dates: "1–2 Mei 2026",
  party: { dewasa: 10, anak: 2, balita: 1 },
  vehicle: "Minibus komersial (Toyota HiAce / Isuzu Elf Long)",
};

const DAY1 = [
  {
    time: "07:00",
    label: "Keberangkatan",
    title: "Sidoarjo — Tol Trans-Jawa",
    place: "Gerbang Tol Sidoarjo",
    tags: ["Mitigasi macet", "Hari Buruh"],
    body: "Usahakan berangkat sebelum 07:00 WIB. Saat Hari Buruh biasanya arus keluar kota padat, terutama di Buduran dan Porong. Setelah itu langsung masuk Tol Trans-Jawa arah Porong–Gempol–Pandaan.",
    note: "Polisi setempat kadang menerapkan penyekatan di perbatasan Sidoarjo–Pasuruan.",
    accent: "depart",
  },
  {
    time: "08:30",
    label: "Rekreasi",
    title: "Dairyland Farm Theme Park Prigen",
    place: "Dataran tinggi Prigen, Pasuruan",
    tags: ["Edutainment", "Anak-anak"],
    body: "Cocok untuk mengisi waktu sebelum check-in pukul 14:00. Area Little Farm dan Milk Museum memungkinkan anak-anak memberi makan domba, sapi, dan rusa. Orang dewasa bisa santai di De Windmills dan Sakura Park.",
    bullets: [
      "Area parkir luas, cukup untuk 2 mobil pribadi",
      "Area rekreasi tersebar, jadi tidak terlalu berdesakan",
      "Spot foto menarik: kincir warna-warni dan pemandangan ala Jepang"
    ],
    alt: {
      title: "Opsi B — Mang Engking Pandaan",
      body: "Kalau tidak ingin aktivitas fisik terlalu banyak, bisa dialihkan ke wisata kuliner pagi. Pilih Mang Engking di Jl. Raya Ledug, atau Warung Bu Is (Rp25–50 ribu/porsi)."
    },
  },
  {
    time: "11:30",
    label: "Ibadah",
    title: "Masjid Agung An-Nuur, Kota Batu",
    place: "Depan Alun-Alun Kota Batu",
    tags: ["Solat Jumat", "Ramah balita"],
    body: "Dipilih sebagai titik utama untuk Salat Jumat. Supaya jadwal tetap nyaman, usahakan rombongan sudah masuk pusat Batu sebelum azan lalu lanjut check-in vila pukul 14:00.",
    pillars: [
      ["Parkir luas", "Tersedia area parkir untuk kendaraan besar"],
      ["Fasilitas kebersihan", "Lebih dari 20 kamar mandi terawat, termasuk akses difabel"],
      ["Ruang laktasi", "Ruang privat dan tenang untuk ibu dan balita"],
      ["Kawasan Tanpa Rokok", "Sesuai Perda No. 10/2020, lebih nyaman untuk anak-anak"]
    ],
    note: "Sarung & mukena pinjaman gratis, dispenser air, ATM Bersama, rest area terpisah.",
  },
  {
    time: "14:00",
    label: "Check-in",
    title: "Villa W1TO",
    place: "Bunga Hotel Resort Club, pusat Kota Batu",
    tags: ["580 m²", "Superhost: Nunung"],
    body: "Vila ini punya 4 kamar tidur, 9 ranjang standar, 5 kasur tambahan ukuran 120 cm, dan 1 roll bed gratis. Total ada 15 opsi tempat tidur untuk 13 orang.",
    villa: true,
  },
  {
    time: "17:30",
    label: "Makan Malam",
    title: "Warung Mbok Sri",
    place: "Jl. Raya Ir. Soekarno No. 105, Beji — dekat Jatim Park 3",
    tags: ["Playground", "Kolam terapi ikan"],
    body: "Menu Nusantara yang cocok untuk keluarga: ikan air tawar, ayam goreng, dan seafood. Ada playground dan kolam terapi ikan, jadi anak-anak tetap terhibur sambil menunggu pesanan untuk 13 porsi.",
    matrix: [
      ["RM Kerta Sari", "Bandeng, Gurami, Wader — taman & patung kolam"],
      ["Pondok Desa", "Latar persawahan, gurami pancing dari bilik kolam"],
      ["Warung Bethania", "Legendaris sejak 1989 — gurami bakar tempo dulu"],
    ],
  },
  {
    time: "19:30",
    label: "Santai",
    title: "Opsi A: Vila · Opsi B: BNS",
    place: "Pilih berdasarkan energi balita",
    tags: ["bebas pilih yang mana"],
    body: "Opsi A (prioritas): kembali ke Villa W1TO untuk santai dengan PlayStation 4 di lantai 1, karaoke di lantai 2, dan BBQ. Opsi B: lanjut ke Batu Night Spectacular untuk Taman Lampion, Cinema 4D, Go-Kart, dan pasar malam.",
    branch: true,
  },
];

const DAY2 = [
  {
    time: "07:00",
    label: "Sarapan",
    title: "Warung Rawon Djamiah Putra",
    place: "Jl. Panglima Sudirman No. 62, Ngaglik",
    tags: ["Buka 06:00 WIB", "Daging tebal"],
    body: "Pas untuk sarapan hangat di udara Batu yang dingin. Rawonnya pakai daging sapi empuk dengan potongan tebal dan bumbu kluwek yang kuat. Buka 06:00–15:30 WIB, sebaiknya datang pagi sebelum ramai.",
    matrix: [
      ["REMPAH Warung Khas Batu", "Menu fusion Nusantara dan western, buka 24 jam, view perbukitan"],
      ["RM Khas Jawa 1985", "Nuansa Jawa klasik, ada gudeg dan rawon, harga terjangkau"],
      ["Warung Nasi Sidik", "Rawon berbumbu kuat, tetapi ruang makannya terbatas untuk 13 orang"],
    ],
  },
  {
    time: "10:00",
    label: "check-out",
    title: "Packing & Check-out Vila",
    place: "Villa W1TO",
    tags: ["Pengecekan final"],
    body: "Selesaikan mandi, bereskan kebutuhan balita, lalu kumpulkan semua barang. Lakukan pengecekan akhir setiap ruangan agar tidak ada yang tertinggal. Check-out maksimal pukul 12:00 WIB.",
  },
  {
    time: "13:00",
    label: "penghijauan",
    title: "Araya Arcade Garden",
    place: "Mansion Hill, Tirtomoyo, Pakis (oleh Rustic Market)",
    tags: ["cafe estetik", "minimal order 100 ribu per orang"],
    body: "Tempat ini memadukan nuansa pedesaan Eropa dengan alam tropis, mirip pedesaan di pegunungan Alpen, Swiss. Hamparan rumput, bunga musiman, dan bangunan kayu membuat suasananya adem. Konsepnya ruang terbuka dan santai, cocok untuk istirahat sejenak.",
    bullets: [
      "Sistem tiket deposit: voucher bisa ditukar penuh untuk F&B",
      "Pizza Corner, Smoke House Steak, Pasta, Salad, Sandwich",
      "Artisan Tea, mixology, smoothies, dan ice cream (favorit anak-anak)",
      "Ada live music dan area bermain balita yang tetap dalam jangkauan pandang orang tua",
    ],
    rules: [
      "Kamera HP — DIPERSILAKAN",
      "Makanan/minuman luar — DILARANG",
    ],
    note: "Tersedia mushola yang nyaman dan toilet terawat, jadi Salat Ashar bisa dilakukan dengan tenang.",
  },
  {
    time: "16:30",
    label: "Oleh-Oleh",
    title: "Sentra Suvenir Pakis",
    place: "Jl. Raya Pakis — sejengkal dari Gerbang Tol Pakis",
    tags: ["menghindari macet Malang"],
    body: "Lokasinya strategis karena Gerbang Tol Pakis langsung terhubung ke Tol Mapan. Rute ini menghindari kepadatan Lawang, Singosari, dan pusat Kota Malang.",
    souvenirs: true,
  },
  {
    time: "18:00",
    label: "Pulang",
    title: "Tol Pakis → Sidoarjo",
    place: "Tol Mapan ↔ Interchange Porong",
    tags: ["Pulang"],
    body: "Perjalanan pulang lewat tol berlangsung lebih lancar. Jalur Malang–Pandaan terhubung ke interchange Porong–Sidoarjo, sehingga diperkirakan tiba kembali di Sidoarjo pada malam hari.",
  },
];

const VILLA_FEATURES = [
  ["4", "Kamar tidur utama"],
  ["15", "Konfigurasi tempat tidur"],
  ["580", "Meter persegi luas"],
  ["100%", "Respons Superhost"],
];

const VILLA_AMENITIES = [
  { lt: "Lt. 1", items: ["PlayStation 4", "Dapur lengkap", "Air galon isi ulang", "Kopi · gula · teh · mi instan"] },
  { lt: "Lt. 2", items: ["Ruang tamu luas", "Karaoke", "BBQ standing", "BBQ portabel"] },
  { lt: "Bonus", items: ["Sekuriti — Pak Fery", "Bebas biaya parkir Baloga", "5 kasur tambahan 120cm gratis", "1 roll bed gratis"] },
];

const SOUVENIRS = [
  {
    name: "Lapis Kukus Tugu Malang",
    addr: "Jl. Raya Pakis No. 112 · 07:00–20:00",
    price: "Rp37.000 – Rp41.000 / kotak",
    shelf: "wajib masuk kulkas",
    variants: ["Original", "Brownies Susu", "Tiramisu", "Talas Keju", "Avocado"],
  },
  {
    name: "Pia Cap Mangkok",
    addr: "Sensa / Trophie · Raya Pakis, Sawojajar",
    price: "Legendaris sejak 1959",
    shelf: "± 14 hari di suhu ruang",
    variants: ["Kacang hijau", "Cokelat", "Durian", "Green tea"],
  },
  {
    name: "Malang Strudel",
    addr: "Sentra Pakis",
    price: "Puff pastry ala Austria",
    shelf: "1–4 hari di suhu ruang · 6 hari di kulkas",
    variants: ["Apel Batu", "Kayu manis", "Kismis", "Brown sugar"],
  },
  {
    name: "Keripik Sanan & Buah",
    addr: "Sentra Pakis",
    price: "Cocok untuk camilan di perjalanan",
    shelf: "kadaluarsa lama karena disegel di plastik",
    variants: ["Tempe Sanan", "Apel", "Nangka", "Rambutan"],
  },
];

// ---------- COMPONENTS ----------
function HeaderHero({ accent, ui }) {
  return (
    <div style={{ padding: "calc(env(safe-area-inset-top, 0px) + 12px) var(--screen-pad) 24px", position: "relative" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 22 }}>
        <div>
          <Mono style={{ color: "#7A6E5A" }}>Rencana Perjalanan</Mono>
          <div style={{ marginTop: 4 }}>
            <Mono style={{ color: accent }}>1–2 Mei 2026 · Jum'at–Sabtu</Mono>
          </div>
        </div>
        <div style={{
          width: 36, height: 36, borderRadius: 18, border: "1px solid #1F2D24",
          display: "flex", alignItems: "center", justifyContent: "center",
          fontFamily: "'Instrument Serif', serif", fontSize: 18, color: "#1F2D24",
        }}>◐</div>
      </div>

      <div style={{
        fontFamily: "'Instrument Serif', serif",
        fontSize: ui.heroTitleSize, lineHeight: 0.95, color: "#1F2D24",
        letterSpacing: -1.5, textWrap: "pretty",
      }}>
        Liburan keluarga<br/>
        <em style={{ fontStyle: "italic", color: accent }}>Ngatepiadji</em><br/>
        ke Batu.
      </div>

      <div style={{ marginTop: 16, display: "flex", gap: 8, flexWrap: "wrap" }}>
        <Pill>Sidoarjo → Batu</Pill>
        <Pill>13 orang</Pill>
        <Pill>2 hari</Pill>
        <Pill>2 Mobil Pribadi</Pill>
      </div>
    </div>
  );
}

function PartyCard({ accent, ui }) {
  return (
    <div style={{ margin: "0 var(--screen-pad) 22px", padding: ui.cardPadding, background: "#FFFBF3", borderRadius: 18, border: "1px solid rgba(31,45,36,0.08)" }}>
      <Mono style={{ color: "#7A6E5A" }}>Komposisi Rombongan</Mono>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(96px, 1fr))", gap: ui.gridGap, marginTop: 14 }}>
        {[
          ["10", "Dewasa"],
          ["2", "Anak kecil"],
          ["1", "Balita"],
        ].map(([n, lab, sub], i) => (
          <div key={i} style={{ borderTop: `2px solid ${i === 2 ? accent : "#1F2D24"}`, paddingTop: 10 }}>
            <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 36, lineHeight: 1, color: "#1F2D24" }}>{n}</div>
            <div style={{ fontSize: 12, fontWeight: 600, marginTop: 6, color: "#1F2D24" }}>{lab}</div>
            <div style={{ fontSize: 10.5, color: "#7A6E5A", marginTop: 3, lineHeight: 1.35 }}>{sub}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

function MitigationStrip({ accent, ui }) {
  return (
    <div style={{ margin: "0 var(--screen-pad) 26px", padding: `${ui.cardPadding}px 18px`, background: "#1F2D24", borderRadius: 18, color: "#F5EFE6" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
        <span style={{ width: 6, height: 6, borderRadius: 3, background: accent }} />
        <Mono style={{ color: "#C9D5C2" }}>Peringatan Hari Buruh</Mono>
      </div>
      <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 22, lineHeight: 1.15, letterSpacing: -0.3 }}>
        Berangkat <em style={{ color: accent, fontStyle: "italic" }}>sebelum 07:00</em> — 1 Mei bertepatan dengan Hari Buruh, biasanya arus keluar kota meningkat.
      </div>
      <div style={{ marginTop: 12, fontSize: 11.5, color: "#C9D5C2", lineHeight: 1.5 }}>
        Titik rawan macet: Buduran → Porong. Penyekatan juga bisa diberlakukan di perbatasan Sidoarjo–Pasuruan.
      </div>
    </div>
  );
}

function TimelineItem({ item, idx, accent, last, onOpen, ui }) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: `${ui.timeColWidth}px 1fr`, gap: 0, position: "relative" }}>
      {/* time rail */}
      <div style={{ position: "relative", paddingTop: 4, paddingRight: 8 }}>
        <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: ui.timeFontSize, color: "#1F2D24", lineHeight: 1 }}>{item.time}</div>
        <Mono style={{
          color: "#7A6E5A",
          display: "block",
          marginTop: 22,
          marginLeft: 0,
          lineHeight: 1.3,
          fontSize: 9.25,
          letterSpacing: 0.3,
          whiteSpace: "nowrap",
        }}>{item.label}</Mono>
        {!last && (
          <div style={{ position: "absolute", left: 6, top: 62, bottom: -22, width: 1, background: "rgba(31,45,36,0.18)" }} />
        )}
        <div style={{ position: "absolute", left: 0, top: 30, width: 13, height: 13, borderRadius: 7, background: "#F5EFE6", border: `2px solid ${accent}` }} />
      </div>

      {/* card */}
      <div onClick={() => onOpen && onOpen(item)} style={{
        background: "#FFFBF3", borderRadius: 16, padding: ui.cardPadding, marginBottom: 18,
        border: "1px solid rgba(31,45,36,0.08)", cursor: onOpen ? "pointer" : "default",
      }}>
        <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: ui.cardTitleSize, lineHeight: 1.1, color: "#1F2D24", letterSpacing: -0.3 }}>
          {item.title}
        </div>
        <div style={{ fontSize: 11, color: "#7A6E5A", marginTop: 4 }}>{item.place}</div>

        <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginTop: 10 }}>
          {item.tags.map((t, i) => <Pill key={i}>{t}</Pill>)}
        </div>

        <div style={{ marginTop: 12, fontSize: 12.5, color: "#3A4A3F", lineHeight: 1.55 }}>
          {item.body}
        </div>

        {item.bullets && (
          <ul style={{ margin: "12px 0 0", padding: 0, listStyle: "none" }}>
            {item.bullets.map((b, i) => (
              <li key={i} style={{ fontSize: 11.5, color: "#3A4A3F", padding: "5px 0", borderTop: "1px dashed rgba(31,45,36,0.12)", display: "flex", gap: 8 }}>
                <span style={{ color: accent, fontFamily: "'JetBrains Mono', monospace" }}>0{i+1}</span>
                <span>{b}</span>
              </li>
            ))}
          </ul>
        )}

        {item.pillars && (
          <div style={{ marginTop: 12, display: "grid", gap: 8 }}>
            {item.pillars.map(([k, v], i) => (
              <div key={i} style={{ display: "grid", gridTemplateColumns: "100px 1fr", gap: 10, paddingTop: 8, borderTop: "1px solid rgba(31,45,36,0.08)" }}>
                <Mono style={{ color: accent }}>{k}</Mono>
                <div style={{ fontSize: 11.5, color: "#3A4A3F", lineHeight: 1.45 }}>{v}</div>
              </div>
            ))}
          </div>
        )}

        {item.matrix && (
          <div style={{ marginTop: 12 }}>
            <Mono style={{ color: "#7A6E5A" }}>Opsi Cadangan</Mono>
            <div style={{ marginTop: 8, display: "grid", gap: 6 }}>
              {item.matrix.map(([n, d], i) => (
                <div key={i} style={{ background: "#F5EFE6", padding: "8px 10px", borderRadius: 10 }}>
                  <div style={{ fontSize: 12, fontWeight: 600, color: "#1F2D24" }}>{n}</div>
                  <div style={{ fontSize: 10.5, color: "#7A6E5A", marginTop: 2 }}>{d}</div>
                </div>
              ))}
            </div>
          </div>
        )}

        {item.alt && (
          <div style={{ marginTop: 12, padding: 12, background: "#F5EFE6", borderRadius: 12, borderLeft: `2px solid ${accent}` }}>
            <Mono style={{ color: accent }}>Opsi Alternatif</Mono>
            <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 16, color: "#1F2D24", marginTop: 4 }}>{item.alt.title}</div>
            <div style={{ fontSize: 11.5, color: "#3A4A3F", marginTop: 4, lineHeight: 1.5 }}>{item.alt.body}</div>
          </div>
        )}

        {item.rules && (
          <div style={{ marginTop: 12, display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 6 }}>
            {item.rules.map((r, i) => {
              const allowed = r.toLowerCase().includes("dipersilakan");
              return (
                <div key={i} style={{
                  fontSize: 10, padding: "8px 10px", borderRadius: 10,
                  background: allowed ? "rgba(107,142,90,0.12)" : "rgba(194,91,63,0.08)",
                  color: allowed ? "#3D5A2E" : "#8B3A22",
                  fontFamily: "'JetBrains Mono', monospace", letterSpacing: 0.3,
                }}>{r}</div>
              );
            })}
          </div>
        )}

        {item.branch && (
          <div style={{ marginTop: 12, display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 8 }}>
            <div style={{ padding: 10, background: "#1F2D24", color: "#F5EFE6", borderRadius: 12 }}>
              <Mono style={{ color: accent }}>Opsi A</Mono>
              <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 16, marginTop: 4 }}>Vila</div>
              <div style={{ fontSize: 10, color: "#C9D5C2", marginTop: 4 }}>PS4 · Karaoke · BBQ</div>
            </div>
            <div style={{ padding: 10, background: "#FFFBF3", borderRadius: 12, border: "1px solid rgba(31,45,36,0.12)" }}>
              <Mono style={{ color: accent }}>Opsi B</Mono>
              <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 16, marginTop: 4, color: "#1F2D24" }}>BNS</div>
              <div style={{ fontSize: 10, color: "#7A6E5A", marginTop: 4 }}>Lampion · Cinema 4D</div>
            </div>
          </div>
        )}

        {item.note && (
          <div style={{ marginTop: 12, padding: 10, background: "rgba(31,45,36,0.04)", borderRadius: 10, fontSize: 10.5, color: "#5C5443", lineHeight: 1.5, fontStyle: "italic" }}>
            {item.note}
          </div>
        )}

        {item.villa && (
          <div style={{ marginTop: 14 }}>
            <img
              src="villa2.avif"
              alt="Foto vila 4 kamar"
              style={{
                width: "100%",
                height: 120,
                objectFit: "cover",
                borderRadius: 14,
                display: "block",
              }}
            />
          </div>
        )}

        {item.souvenirs && (
          <div style={{ marginTop: 12, display: "grid", gap: 8 }}>
            {SOUVENIRS.map((s, i) => (
              <div key={i} style={{ padding: 12, background: "#F5EFE6", borderRadius: 12 }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
                  <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 17, color: "#1F2D24" }}>{s.name}</div>
                  <Mono style={{ color: accent }}>0{i+1}</Mono>
                </div>
                <div style={{ fontSize: 10.5, color: "#7A6E5A", marginTop: 3 }}>{s.addr}</div>
                <div style={{ fontSize: 10.5, color: "#3A4A3F", marginTop: 6 }}>{s.price}</div>
                <div style={{ fontSize: 10, color: "#7A6E5A", marginTop: 2, fontStyle: "italic" }}>{s.shelf}</div>
                <div style={{ marginTop: 8, display: "flex", flexWrap: "wrap", gap: 4 }}>
                  {s.variants.map((v, j) => (
                    <span key={j} style={{ fontSize: 10, padding: "3px 7px", borderRadius: 999, border: "1px solid rgba(31,45,36,0.18)", color: "#1F2D24" }}>{v}</span>
                  ))}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function DayPanel({ day, items, dateLabel, accent, ui }) {
  return (
    <div style={{ padding: "8px var(--screen-pad) 30px" }}>
      <div style={{ paddingTop: 8, paddingBottom: 18, borderBottom: "1px solid rgba(31,45,36,0.1)", marginBottom: 22 }}>
        <Mono style={{ color: "#7A6E5A" }}>Hari {day === 1 ? "Pertama" : "Kedua"}</Mono>
        <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 40, color: "#1F2D24", lineHeight: 1, marginTop: 6, letterSpacing: -1 }}>
          {dateLabel}
        </div>
        <div style={{ fontSize: 12, color: "#7A6E5A", marginTop: 8 }}>
          {day === 1 ? "Sidoarjo → Prigen → Batu" : "Batu → Pakis → Sidoarjo"}
        </div>
      </div>
      {items.map((it, i) => (
        <TimelineItem key={i} item={it} idx={i} accent={accent} last={i === items.length - 1} ui={ui} />
      ))}
    </div>
  );
}

function VillaPanel({ accent, ui }) {
  return (
    <div style={{ padding: "8px var(--screen-pad) 30px" }}>
      <div style={{ paddingTop: 8, paddingBottom: 18, marginBottom: 18 }}>
        <Mono style={{ color: "#7A6E5A" }}>Akomodasi Utama</Mono>
        <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 44, color: "#1F2D24", lineHeight: 0.98, marginTop: 6, letterSpacing: -1.2 }}>
          Villa <em style={{ fontStyle: "italic", color: accent }}>W1TO</em>
        </div>
        <div style={{ fontSize: 12, color: "#7A6E5A", marginTop: 8, lineHeight: 1.5 }}>
          Bunga Hotel Resort Club, pusat Kota Batu. Check-in 14:00 · Check-out 12:00.
        </div>
      </div>

      <img
        src="villa1.avif"
        alt="Foto eksterior vila"
        style={{
          width: "100%",
          height: 180,
          objectFit: "cover",
          borderRadius: 14,
          display: "block",
        }}
      />

      <div style={{ marginTop: 18, display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 10 }}>
        {VILLA_FEATURES.map(([n, l], i) => (
          <div key={i} style={{ background: "#FFFBF3", borderRadius: 14, padding: 14, border: "1px solid rgba(31,45,36,0.08)" }}>
            <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 36, color: "#1F2D24", lineHeight: 1, letterSpacing: -1 }}>{n}</div>
            <div style={{ fontSize: 11, color: "#7A6E5A", marginTop: 4 }}>{l}</div>
          </div>
        ))}
      </div>

      <div style={{ marginTop: 18, padding: 16, background: "#1F2D24", borderRadius: 16, color: "#F5EFE6" }}>
        <Mono style={{ color: accent }}>Konfigurasi Tidur</Mono>
        <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 20, marginTop: 6, lineHeight: 1.2 }}>
          9 ranjang standar + 5 kasur tambahan 120cm + 1 roll bed = <em style={{ color: accent }}>15 untuk 13 orang</em>
        </div>
      </div>

      <div style={{ marginTop: 18 }}>
        {VILLA_AMENITIES.map((g, i) => (
          <div key={i} style={{ marginBottom: 14 }}>
            <Mono style={{ color: accent }}>{g.lt}</Mono>
            <div style={{ marginTop: 8, display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))", gap: 6 }}>
              {g.items.map((it, j) => (
                <div key={j} style={{ fontSize: 11.5, color: "#1F2D24", padding: "10px 12px", background: "#FFFBF3", borderRadius: 10, border: "1px solid rgba(31,45,36,0.08)" }}>
                  {it}
                </div>
              ))}
            </div>
          </div>
        ))}
      </div>

      <div style={{ marginTop: 18, padding: 14, background: "#FFFBF3", borderRadius: 14, border: `1px dashed ${accent}` }}>
        <Mono style={{ color: accent }}>Catatan Host</Mono>
        <div style={{ fontSize: 12, color: "#3A4A3F", marginTop: 6, lineHeight: 1.55 }}>
          Pemilik <strong>Nunung</strong> (Superhost Airbnb, respons 100%) menyediakan kasur tambahan tanpa biaya. Sekuriti <strong>Bapak Fery</strong>. Bebas biaya parkir di Batu Love Garden — cukup identifikasi verbal sebagai tamu vila.
        </div>
      </div>
    </div>
  );
}

function OverviewPanel({ accent, onJump, ui }) {
  return (
    <>
      <HeaderHero accent={accent} ui={ui} />
      <PartyCard accent={accent} ui={ui} />
      <MitigationStrip accent={accent} ui={ui} />

      <div style={{ padding: "0 var(--screen-pad) 8px" }}>
        <Mono style={{ color: "#7A6E5A" }}>Ringkasan 2 Hari</Mono>
      </div>

      <div style={{ padding: "8px var(--screen-pad) 30px" }}>
        {[
          { day: 1, title: "Berangkat Pagi & Wisata Batu", date: "Jumat, 1 Mei", flow: "Sidoarjo → Prigen → Batu", k: "day1" },
          { day: 2, title: "Kuliner, Santai, Lalu Pulang", date: "Sabtu, 2 Mei", flow: "Batu → Pakis → Sidoarjo", k: "day2" },
        ].map((d, i) => (
          <div key={i} onClick={() => onJump(d.k)} style={{
            marginBottom: 12, padding: 18, background: i === 0 ? "#1F2D24" : "#FFFBF3",
            color: i === 0 ? "#F5EFE6" : "#1F2D24", borderRadius: 18,
            border: i === 1 ? "1px solid rgba(31,45,36,0.08)" : "none", cursor: "pointer",
          }}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline" }}>
              <Mono style={{ color: i === 0 ? "#C9D5C2" : "#7A6E5A" }}>Hari ke-{d.day}</Mono>
              <Mono style={{ color: accent }}>{d.date}</Mono>
            </div>
            <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 30, lineHeight: 1.05, marginTop: 8, letterSpacing: -0.6 }}>
              {d.title}
            </div>
            <div style={{ fontSize: 11, marginTop: 10, opacity: 0.75 }}>{d.flow}</div>
          </div>
        ))}
      </div>

      <div style={{ padding: "0 var(--screen-pad) 30px" }}>
        <Mono style={{ color: "#7A6E5A" }}>Kata-kata hari ini</Mono>
        <div style={{ fontFamily: "'Instrument Serif', serif", fontSize: 18, color: "#1F2D24", marginTop: 8, lineHeight: 1.3, fontStyle: "italic" }}>
          "Meninggalkan sejenak urusan dunia demi berburu momen seru dan menciptakan tradisi baru bareng keluarga."
        </div>
      </div>
    </>
  );
}

// ---------- BOTTOM NAV ----------
function BottomNav({ tab, setTab, accent, ui }) {
  const tabs = [
    { k: "overview", label: "Ringkasan", icon: "◐" },
    { k: "day1", label: "Hari 1", icon: "①" },
    { k: "day2", label: "Hari 2", icon: "②" },
    { k: "villa", label: "Penginapan", icon: "⌂" },
  ];
  return (
    <div style={{
      flexShrink: 0,
      background: "rgba(245,239,230,0.92)", backdropFilter: "blur(20px)",
      borderTop: "1px solid rgba(31,45,36,0.1)",
      minHeight: `calc(${ui.navBodyHeight}px + env(safe-area-inset-bottom, 0px))`,
      paddingBottom: "env(safe-area-inset-bottom, 0px)",
      display: "flex",
      alignItems: "center",
      justifyContent: "space-around",
    }}>
      {tabs.map(t => (
        <div key={t.k} onClick={() => setTab(t.k)} style={{
          display: "flex", flexDirection: "column", alignItems: "center", gap: 5,
          padding: "4px 0", cursor: "pointer", flex: 1,
        }}>
          <div style={{ fontSize: ui.navIconSize, color: tab === t.k ? accent : "#7A6E5A" }}>{t.icon}</div>
          <div style={{
            fontFamily: "'JetBrains Mono', monospace", fontSize: ui.navLabelSize, letterSpacing: 0.5,
            textTransform: "uppercase", color: tab === t.k ? "#1F2D24" : "#7A6E5A",
            fontWeight: tab === t.k ? 600 : 400,
          }}>{t.label}</div>
        </div>
      ))}
    </div>
  );
}

// ---------- APP ----------
function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [tab, setTab] = useState("overview");
  const [viewportWidth, setViewportWidth] = useState(() => Math.min(window.innerWidth || 430, 430));
  const scrollRef = useRef(null);
  const accent = ACCENTS[tweaks.accent].c;
  const is390 = viewportWidth <= 390;
  const ui = useMemo(() => ({
    screenPad: is390 ? 14 : 22,
    heroTitleSize: is390 ? 50 : 56,
    cardPadding: is390 ? 14 : 16,
    gridGap: is390 ? 10 : 12,
    timeColWidth: is390 ? 78 : 84,
    timeFontSize: is390 ? 20 : 22,
    cardTitleSize: is390 ? 20 : 22,
    navBodyHeight: is390 ? 60 : 64,
    navIconSize: is390 ? 15 : 16,
    navLabelSize: is390 ? 9 : 9.5,
  }), [is390]);

  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = 0;
  }, [tab]);

  useEffect(() => {
    const onResize = () => setViewportWidth(Math.min(window.innerWidth || 430, 430));
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);

  const content = (
    <div style={{
      "--screen-pad": `${ui.screenPad}px`,
      width: "100%",
      height: "100%",
      display: "flex",
      flexDirection: "column",
      background: "#F5EFE6",
      color: "#1F2D24",
      fontFamily: "'Geist', -apple-system, system-ui, sans-serif",
    }}>
      <div ref={scrollRef} style={{
        flex: 1,
        overflowY: "auto",
        overflowX: "hidden",
        WebkitOverflowScrolling: "touch",
      }} data-screen-label={tab}>
        <div style={{ height: "max(10px, env(safe-area-inset-top, 0px))" }} />

        {tab === "overview" && <OverviewPanel accent={accent} onJump={setTab} ui={ui} />}
        {tab === "day1" && <DayPanel day={1} items={DAY1} dateLabel="Jumat, 01 Mei" accent={accent} ui={ui} />}
        {tab === "day2" && <DayPanel day={2} items={DAY2} dateLabel="Sabtu, 02 Mei" accent={accent} ui={ui} />}
        {tab === "villa" && <VillaPanel accent={accent} ui={ui} />}
      </div>
      <BottomNav tab={tab} setTab={setTab} accent={accent} ui={ui} />
    </div>
  );

  return (
    <div style={{
      minHeight: "100svh", display: "flex", alignItems: "stretch", justifyContent: "center",
      background: "#1F2D24",
      backgroundImage: "radial-gradient(circle at 20% 10%, #2A3B30 0%, #1F2D24 40%, #16201B 100%)",
      padding: 0, fontFamily: "'Geist', sans-serif",
    }}>
      <div style={{
        width: "100%",
        maxWidth: 430,
        height: "100svh",
        overflow: "hidden",
        boxShadow: "0 20px 50px rgba(0,0,0,0.25)",
      }}>
        {content}
      </div>

      <TweaksPanel title="Tweaks">
        <TweakSection title="Aksen warna">
          <TweakRadio
            value={tweaks.accent}
            onChange={v => setTweak("accent", v)}
            options={Object.entries(ACCENTS).map(([k, v]) => ({ value: k, label: v.name }))}
          />
        </TweakSection>
      </TweaksPanel>
    </div>
  );
}

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