Files
lampada-monica/app.js
2026-03-17 20:59:58 +01:00

189 lines
39 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const DAYS = [{"id": "d14", "date": "14 giugno", "title": "Tokyo moderna", "city": "Tokyo", "base": "Asakusa", "summary": "Arrivo, Meiji Jingu, Shibuya e Shinjuku.", "budget_jpy": [18000, 28000], "hint": "Non correte: primo highlight Meiji Jingu.", "weather_city": "Tokyo, Japan", "timeline": [["08:50", "Narita", "Arrivo", "Narita International Airport"], ["10:30", "Asakusa", "Check-in", "AMANEK Asakusa Sakurabashi"], ["15:00", "Meiji Jingu", "Passeggiata", "Meiji Jingu"], ["18:00", "Shibuya", "Crossing", "Shibuya Crossing"], ["19:45", "Shinjuku", "Cena", "Omoide Yokocho"]], "lunch": {"area": "Asakusa", "places": [{"name": "Yoshikami", "query": "Yoshikami Asakusa Tokyo"}, {"name": "Daikokuya Tempura", "query": "Daikokuya Tempura Asakusa Tokyo"}, {"name": "Opzione pranzo 3 · Asakusa", "query": "lunch Asakusa Tokyo Japan"}, {"name": "Opzione pranzo 4 · Asakusa", "query": "lunch Asakusa Tokyo Japan"}, {"name": "Opzione pranzo 5 · Asakusa", "query": "lunch Asakusa Tokyo Japan"}]}, "dinner": {"area": "Shinjuku", "places": [{"name": "Kamo to Negi", "query": "Kamo to Negi Shinjuku Tokyo"}, {"name": "Tsunahachi", "query": "Tsunahachi Shinjuku Tokyo"}, {"name": "Opzione cena 3 · Shinjuku", "query": "dinner Shinjuku Tokyo Japan"}, {"name": "Opzione cena 4 · Shinjuku", "query": "dinner Shinjuku Tokyo Japan"}, {"name": "Opzione cena 5 · Shinjuku", "query": "dinner Shinjuku Tokyo Japan"}]}, "onsen": [{"name": "Thermae-Yu Shinjuku", "query": "Thermae-Yu Shinjuku Tokyo"}, {"name": "Asakusa ROX Matsuri-yu", "query": "Asakusa ROX Matsuri-yu Tokyo"}, {"name": "Mikokuyu (sento)", "query": "Mikokuyu Sumida Tokyo"}], "love_hotels": [{"name": "Bali An Resort Shinjuku Forest", "query": "Hotel Bali An Resort Shinjuku Forest Tokyo"}, {"name": "HOTEL & SPA AN Shinjuku Kabukicho", "query": "HOTEL & SPA AN Shinjuku Kabukicho Tokyo"}, {"name": "HOTEL & SPA J-MEX Shinjuku", "query": "HOTEL & SPA J-MEX Shinjuku Tokyo"}]}, {"id": "d15", "date": "15 giugno", "title": "Tokyo tradizionale", "city": "Tokyo", "base": "Asakusa", "summary": "Senso-ji, Skytree, Ueno e Akihabara.", "budget_jpy": [16000, 30000], "hint": "Entrate presto a Senso-ji.", "weather_city": "Tokyo, Japan", "timeline": [["09:00", "Senso-ji", "Tempio e Nakamise", "Senso-ji"], ["11:00", "Tokyo Skytree", "Vista", "Tokyo Skytree"], ["14:40", "Ueno Park", "Passeggiata", "Ueno Park"], ["17:30", "Akihabara", "Anime ed elettronica", "Akihabara Station"]], "lunch": {"area": "Asakusa / Solamachi", "places": [{"name": "Sushi Zanmai Asakusa", "query": "Sushi Zanmai Asakusa Tokyo"}, {"name": "Tokyo Solamachi food hall", "query": "Tokyo Solamachi Tokyo"}, {"name": "Opzione pranzo 3 · Asakusa / Solamachi", "query": "lunch Asakusa / Solamachi Tokyo Japan"}, {"name": "Opzione pranzo 4 · Asakusa / Solamachi", "query": "lunch Asakusa / Solamachi Tokyo Japan"}, {"name": "Opzione pranzo 5 · Asakusa / Solamachi", "query": "lunch Asakusa / Solamachi Tokyo Japan"}]}, "dinner": {"area": "Akihabara / Asakusa", "places": [{"name": "Gyukatsu Motomura Akihabara", "query": "Gyukatsu Motomura Akihabara Tokyo"}, {"name": "Izakaya vicino ad Asakusa", "query": "Izakaya Asakusa Tokyo"}, {"name": "Opzione cena 3 · Akihabara / Asakusa", "query": "dinner Akihabara / Asakusa Tokyo Japan"}, {"name": "Opzione cena 4 · Akihabara / Asakusa", "query": "dinner Akihabara / Asakusa Tokyo Japan"}, {"name": "Opzione cena 5 · Akihabara / Asakusa", "query": "dinner Akihabara / Asakusa Tokyo Japan"}]}, "onsen": [{"name": "Asakusa ROX Matsuri-yu", "query": "Asakusa ROX Matsuri-yu Tokyo"}, {"name": "Thermae-Yu Shinjuku", "query": "Thermae-Yu Shinjuku Tokyo"}, {"name": "Daikokuyu (Asakusa area)", "query": "Daikokuyu Tokyo"}], "love_hotels": [{"name": "Bali An Resort Shinjuku Forest", "query": "Hotel Bali An Resort Shinjuku Forest Tokyo"}, {"name": "HOTEL & SPA AN Shinjuku Kabukicho", "query": "HOTEL & SPA AN Shinjuku Kabukicho Tokyo"}, {"name": "HOTEL & SPA J-MEX Shinjuku", "query": "HOTEL & SPA J-MEX Shinjuku Tokyo"}]}, {"id": "d16", "date": "16 giugno", "title": "teamLab + Tsukiji + Odaiba", "city": "Tokyo", "base": "Asakusa", "summary": "Arte immersiva, mercato, giardini e waterfront.", "budget_jpy": [22000, 36000], "hint": "teamLab va vissuto con calma.", "weather_city": "Tokyo, Japan", "timeline": [["09:30", "teamLab Planets", "Ingresso prenotato", "teamLab Planets TOKYO"], ["12:30", "Tsukiji", "Pranzo seafood", "Tsukiji Outer Market"], ["14:30", "Hama-rikyu", "Giardini", "Hama-rikyu Gardens"], ["16:40", "Odaiba", "Passeggiata", "The Gundam Base Tokyo"]], "lunch": {"area": "Tsukiji", "places": [{"name": "Sushizanmai Tsukiji", "query": "Sushizanmai Tsukiji Tokyo"}, {"name": "Tsukiji Itadori Bekkan", "query": "Tsukiji Itadori Bekkan Tokyo"}, {"name": "Opzione pranzo 3 · Tsukiji", "query": "lunch Tsukiji Tokyo Japan"}, {"name": "Opzione pranzo 4 · Tsukiji", "query": "lunch Tsukiji Tokyo Japan"}, {"name": "Opzione pranzo 5 · Tsukiji", "query": "lunch Tsukiji Tokyo Japan"}]}, "dinner": {"area": "Odaiba / Asakusa", "places": [{"name": "Bills Odaiba", "query": "Bills Odaiba Tokyo"}, {"name": "Ramen rientro Asakusa", "query": "Ramen Asakusa Tokyo"}, {"name": "Opzione cena 3 · Odaiba / Asakusa", "query": "dinner Odaiba / Asakusa Tokyo Japan"}, {"name": "Opzione cena 4 · Odaiba / Asakusa", "query": "dinner Odaiba / Asakusa Tokyo Japan"}, {"name": "Opzione cena 5 · Odaiba / Asakusa", "query": "dinner Odaiba / Asakusa Tokyo Japan"}]}, "onsen": [{"name": "Asakusa ROX Matsuri-yu", "query": "Asakusa ROX Matsuri-yu Tokyo"}, {"name": "Thermae-Yu Shinjuku", "query": "Thermae-Yu Shinjuku Tokyo"}, {"name": "Daikokuyu (Asakusa area)", "query": "Daikokuyu Tokyo"}], "love_hotels": [{"name": "Bali An Resort Shinjuku Forest", "query": "Hotel Bali An Resort Shinjuku Forest Tokyo"}, {"name": "HOTEL & SPA AN Shinjuku Kabukicho", "query": "HOTEL & SPA AN Shinjuku Kabukicho Tokyo"}, {"name": "HOTEL & SPA J-MEX Shinjuku", "query": "HOTEL & SPA J-MEX Shinjuku Tokyo"}]}, {"id": "d17", "date": "17 giugno", "title": "Kamakura", "city": "Kamakura", "base": "Asakusa", "summary": "Grande Buddha, Hasedera, centro storico e spiaggia.", "budget_jpy": [18000, 30000], "hint": "Non riempite troppo la giornata.", "weather_city": "Kamakura, Japan", "timeline": [["07:45", "Kamakura", "Partenza presto", "Kamakura Station"], ["10:00", "Kotoku-in", "Grande Buddha", "Kotoku-in"], ["11:00", "Hasedera", "Tempio e giardini", "Hasedera Temple"], ["14:00", "Komachi-dori", "Passeggiata", "Komachi-dori Street"], ["15:30", "Yuigahama", "Relax", "Yuigahama Beach"]], "lunch": {"area": "Kamakura", "places": [{"name": "Matsubara-an Komachi", "query": "Matsubara-an Komachi Kamakura"}, {"name": "Shirasu-don Komachi-dori", "query": "Shirasu don Komachi dori Kamakura"}, {"name": "Opzione pranzo 3 · Kamakura", "query": "lunch Kamakura Kamakura Japan"}, {"name": "Opzione pranzo 4 · Kamakura", "query": "lunch Kamakura Kamakura Japan"}, {"name": "Opzione pranzo 5 · Kamakura", "query": "lunch Kamakura Kamakura Japan"}]}, "dinner": {"area": "Asakusa", "places": [{"name": "Cena semplice Asakusa", "query": "Restaurant Asakusa Tokyo"}, {"name": "Soba Asakusa", "query": "Soba Asakusa Tokyo"}, {"name": "Opzione cena 3 · Asakusa", "query": "dinner Asakusa Kamakura Japan"}, {"name": "Opzione cena 4 · Asakusa", "query": "dinner Asakusa Kamakura Japan"}, {"name": "Opzione cena 5 · Asakusa", "query": "dinner Asakusa Kamakura Japan"}]}, "onsen": [{"name": "Inamuragasaki Onsen", "query": "Inamuragasaki Onsen Kamakura"}, {"name": "Enoshima Island Spa", "query": "Enoshima Island Spa"}, {"name": "Tattoo friendly bath near Kamakura", "query": "tattoo friendly bath Kamakura"}], "love_hotels": [{"name": "Love hotel in zona", "query": "love hotel Kamakura Japan"}, {"name": "Adult only hotel in zona", "query": "adult only hotel Kamakura Japan"}, {"name": "Short stay hotel in zona", "query": "short stay hotel Kamakura Japan"}]}, {"id": "d18", "date": "18 giugno", "title": "Tokyo → Kanazawa", "city": "Kanazawa", "base": "Kanazawa", "summary": "Shinkansen, Omicho Market e quartiere samurai.", "budget_jpy": [38000, 55000], "hint": "Mercato + quartiere samurai bastano.", "weather_city": "Kanazawa, Japan", "timeline": [["08:30", "Kanazawa", "Shinkansen", "Kanazawa Station"], ["12:15", "Omicho Market", "Pranzo", "Omicho Market"], ["14:30", "Nagamachi", "Passeggiata quartiere samurai", "Nagamachi Samurai District"], ["19:30", "Katamachi", "Cena", "Katamachi"]], "lunch": {"area": "Omicho Market", "places": [{"name": "Mori Mori Sushi", "query": "Mori Mori Sushi Omicho Kanazawa"}, {"name": "Iki-Iki Tei", "query": "Iki-Iki Tei Omicho Kanazawa"}, {"name": "Opzione pranzo 3 · Omicho Market", "query": "lunch Omicho Market Kanazawa Japan"}, {"name": "Opzione pranzo 4 · Omicho Market", "query": "lunch Omicho Market Kanazawa Japan"}, {"name": "Opzione pranzo 5 · Omicho Market", "query": "lunch Omicho Market Kanazawa Japan"}]}, "dinner": {"area": "Katamachi", "places": [{"name": "Izakaya Katamachi", "query": "Izakaya Katamachi Kanazawa"}, {"name": "Sushi di Kanazawa", "query": "Sushi Katamachi Kanazawa"}, {"name": "Opzione cena 3 · Katamachi", "query": "dinner Katamachi Kanazawa Japan"}, {"name": "Opzione cena 4 · Katamachi", "query": "dinner Katamachi Kanazawa Japan"}, {"name": "Opzione cena 5 · Katamachi", "query": "dinner Katamachi Kanazawa Japan"}]}, "onsen": [{"name": "Kashikiri / private bath Kanazawa", "query": "private onsen Kanazawa"}, {"name": "Ryokan private bath Kanazawa", "query": "ryokan private bath Kanazawa"}, {"name": "Tattoo friendly sento Kanazawa", "query": "tattoo friendly sento Kanazawa"}], "love_hotels": [{"name": "Love hotel in zona", "query": "love hotel Kanazawa Japan"}, {"name": "Adult only hotel in zona", "query": "adult only hotel Kanazawa Japan"}, {"name": "Short stay hotel in zona", "query": "short stay hotel Kanazawa Japan"}]}, {"id": "d19", "date": "19 giugno", "title": "Kanazawa classica", "city": "Kanazawa", "base": "Kanazawa", "summary": "Kenroku-en, castello e Higashi Chaya.", "budget_jpy": [18000, 35000], "hint": "Kenroku-en va fatto lentamente.", "weather_city": "Kanazawa, Japan", "timeline": [["09:15", "Kenroku-en", "Visita", "Kenroku-en"], ["11:30", "Kanazawa Castle", "Passaggio dal giardino al castello", "Kanazawa Castle"], ["13:10", "Higashi Chaya", "Passeggiata e tè", "Higashi Chaya District"], ["18:30", "Centro", "Cena", "Katamachi"]], "lunch": {"area": "Centro / Higashi Chaya", "places": [{"name": "Soba in centro", "query": "Soba Kanazawa city center"}, {"name": "Omicho Market bis", "query": "Omicho Market Kanazawa"}, {"name": "Opzione pranzo 3 · Centro / Higashi Chaya", "query": "lunch Centro / Higashi Chaya Kanazawa Japan"}, {"name": "Opzione pranzo 4 · Centro / Higashi Chaya", "query": "lunch Centro / Higashi Chaya Kanazawa Japan"}, {"name": "Opzione pranzo 5 · Centro / Higashi Chaya", "query": "lunch Centro / Higashi Chaya Kanazawa Japan"}]}, "dinner": {"area": "Katamachi", "places": [{"name": "Izakaya Katamachi", "query": "Izakaya Katamachi Kanazawa"}, {"name": "Sushi di Kanazawa", "query": "Sushi Kanazawa Katamachi"}, {"name": "Opzione cena 3 · Katamachi", "query": "dinner Katamachi Kanazawa Japan"}, {"name": "Opzione cena 4 · Katamachi", "query": "dinner Katamachi Kanazawa Japan"}, {"name": "Opzione cena 5 · Katamachi", "query": "dinner Katamachi Kanazawa Japan"}]}, "onsen": [{"name": "Kashikiri / private bath Kanazawa", "query": "private onsen Kanazawa"}, {"name": "Ryokan private bath Kanazawa", "query": "ryokan private bath Kanazawa"}, {"name": "Tattoo friendly sento Kanazawa", "query": "tattoo friendly sento Kanazawa"}], "love_hotels": [{"name": "Love hotel in zona", "query": "love hotel Kanazawa Japan"}, {"name": "Adult only hotel in zona", "query": "adult only hotel Kanazawa Japan"}, {"name": "Short stay hotel in zona", "query": "short stay hotel Kanazawa Japan"}]}, {"id": "d20", "date": "20 giugno", "title": "Shirakawa-go + Kyoto", "city": "Kyoto", "base": "Kyoto", "summary": "Villaggio UNESCO e trasferimento a Kyoto.", "budget_jpy": [35000, 50000], "hint": "Fate il viewpoint e poi rilassatevi.", "weather_city": "Kyoto, Japan", "timeline": [["08:10", "Shirakawa-go", "Bus espresso", "Shirakawa-go Bus Terminal"], ["09:35", "Shirakawa-go", "Villaggio + viewpoint", "Shirakawa-go"], ["16:00", "Kyoto", "Trasferimento", "Kyoto Station"], ["18:30", "Kyoto", "Check-in", "M's Plus Shijo Omiya"]], "lunch": {"area": "Shirakawa-go", "places": [{"name": "Irori", "query": "Irori Shirakawa-go"}, {"name": "Soba nel villaggio", "query": "Soba Shirakawa-go"}, {"name": "Opzione pranzo 3 · Shirakawa-go", "query": "lunch Shirakawa-go Kyoto Japan"}, {"name": "Opzione pranzo 4 · Shirakawa-go", "query": "lunch Shirakawa-go Kyoto Japan"}, {"name": "Opzione pranzo 5 · Shirakawa-go", "query": "lunch Shirakawa-go Kyoto Japan"}]}, "dinner": {"area": "Kyoto hotel area", "places": [{"name": "Ramen vicino allhotel", "query": "Ramen Shijo Omiya Kyoto"}, {"name": "Izakaya vicino allhotel", "query": "Izakaya Shijo Omiya Kyoto"}, {"name": "Opzione cena 3 · Kyoto hotel area", "query": "dinner Kyoto hotel area Kyoto Japan"}, {"name": "Opzione cena 4 · Kyoto hotel area", "query": "dinner Kyoto hotel area Kyoto Japan"}, {"name": "Opzione cena 5 · Kyoto hotel area", "query": "dinner Kyoto hotel area Kyoto Japan"}]}, "onsen": [{"name": "Arashiyama Onsen Kadensho", "query": "Arashiyama Onsen Kadensho Kyoto"}, {"name": "Hanaikada", "query": "Hanaikada Arashiyama Kyoto"}, {"name": "Fufu no Yu", "query": "Fufu no Yu Kyoto"}], "love_hotels": [{"name": "Hotel In The Green", "query": "Hotel In The Green Kyoto"}, {"name": "Hotel Chronos - Adult Only", "query": "Hotel Chronos Kyoto"}, {"name": "Hotel & Spa Lotus", "query": "Hotel & Spa Lotus Kyoto"}]}, {"id": "d21", "date": "21 giugno", "title": "Arashiyama + Kinkaku-ji", "city": "Kyoto", "base": "Kyoto", "summary": "Bamboo grove, Tenryu-ji, onsen e Kinkaku-ji.", "budget_jpy": [18000, 34000], "hint": "Bamboo grove presto, poi rallentate.", "weather_city": "Kyoto, Japan", "timeline": [["08:30", "Arashiyama", "Randen", "Arashiyama Bamboo Grove"], ["09:50", "Tenryu-ji", "Tempio e giardini", "Tenryu-ji"], ["13:15", "Fufu-no-yu", "Onsen", "Fufu-no-yu"], ["16:45", "Kinkaku-ji", "Visita", "Kinkaku-ji"]], "lunch": {"area": "Arashiyama", "places": [{"name": "Saga Tofu Ine", "query": "Saga Tofu Ine Arashiyama Kyoto"}, {"name": "Arashiyama Yoshimura", "query": "Arashiyama Yoshimura Kyoto"}, {"name": "Opzione pranzo 3 · Arashiyama", "query": "lunch Arashiyama Kyoto Japan"}, {"name": "Opzione pranzo 4 · Arashiyama", "query": "lunch Arashiyama Kyoto Japan"}, {"name": "Opzione pranzo 5 · Arashiyama", "query": "lunch Arashiyama Kyoto Japan"}]}, "dinner": {"area": "Centro Kyoto", "places": [{"name": "Ramen in centro", "query": "Ramen central Kyoto"}, {"name": "Izakaya centro Kyoto", "query": "Izakaya central Kyoto"}, {"name": "Opzione cena 3 · Centro Kyoto", "query": "dinner Centro Kyoto Kyoto Japan"}, {"name": "Opzione cena 4 · Centro Kyoto", "query": "dinner Centro Kyoto Kyoto Japan"}, {"name": "Opzione cena 5 · Centro Kyoto", "query": "dinner Centro Kyoto Kyoto Japan"}]}, "onsen": [{"name": "Arashiyama Onsen Kadensho", "query": "Arashiyama Onsen Kadensho Kyoto"}, {"name": "Hanaikada", "query": "Hanaikada Arashiyama Kyoto"}, {"name": "Fufu no Yu", "query": "Fufu no Yu Kyoto"}], "love_hotels": [{"name": "Hotel In The Green", "query": "Hotel In The Green Kyoto"}, {"name": "Hotel Chronos - Adult Only", "query": "Hotel Chronos Kyoto"}, {"name": "Hotel & Spa Lotus", "query": "Hotel & Spa Lotus Kyoto"}]}, {"id": "d22", "date": "22 giugno", "title": "Nara + Fushimi Inari + Gion", "city": "Kyoto", "base": "Kyoto", "summary": "Nara, Grande Buddha, torii rossi e Gion.", "budget_jpy": [20000, 38000], "hint": "Salite un po a Fushimi Inari.", "weather_city": "Kyoto, Japan", "timeline": [["09:00", "Nara", "Trasferimento", "Nara Park"], ["10:50", "Todai-ji", "Grande Buddha", "Todai-ji"], ["15:30", "Fushimi Inari", "Torii rossi", "Fushimi Inari Taisha"], ["19:00", "Gion/Pontocho", "Cena e passeggiata", "Gion Kyoto"]], "lunch": {"area": "Nara", "places": [{"name": "Set lunch vicino al parco", "query": "Lunch Nara Park"}, {"name": "Soba a Nara", "query": "Soba Nara Park"}, {"name": "Opzione pranzo 3 · Nara", "query": "lunch Nara Kyoto Japan"}, {"name": "Opzione pranzo 4 · Nara", "query": "lunch Nara Kyoto Japan"}, {"name": "Opzione pranzo 5 · Nara", "query": "lunch Nara Kyoto Japan"}]}, "dinner": {"area": "Gion / Pontocho", "places": [{"name": "Cena speciale Gion", "query": "Restaurant Gion Kyoto"}, {"name": "Cena Pontocho", "query": "Restaurant Pontocho Kyoto"}, {"name": "Opzione cena 3 · Gion / Pontocho", "query": "dinner Gion / Pontocho Kyoto Japan"}, {"name": "Opzione cena 4 · Gion / Pontocho", "query": "dinner Gion / Pontocho Kyoto Japan"}, {"name": "Opzione cena 5 · Gion / Pontocho", "query": "dinner Gion / Pontocho Kyoto Japan"}]}, "onsen": [{"name": "Arashiyama Onsen Kadensho", "query": "Arashiyama Onsen Kadensho Kyoto"}, {"name": "Hanaikada", "query": "Hanaikada Arashiyama Kyoto"}, {"name": "Fufu no Yu", "query": "Fufu no Yu Kyoto"}], "love_hotels": [{"name": "Hotel In The Green", "query": "Hotel In The Green Kyoto"}, {"name": "Hotel Chronos - Adult Only", "query": "Hotel Chronos Kyoto"}, {"name": "Hotel & Spa Lotus", "query": "Hotel & Spa Lotus Kyoto"}]}, {"id": "d23", "date": "23 giugno", "title": "Kyoto storica + Nishiki + Otagi", "city": "Kyoto", "base": "Kyoto", "summary": "Castello, mercato e tempio laterale pieno di carattere.", "budget_jpy": [18000, 35000], "hint": "Otagi è il vero jolly.", "weather_city": "Kyoto, Japan", "timeline": [["09:00", "Nijo Castle", "Ingresso presto", "Nijo Castle"], ["12:00", "Nishiki Market", "Pranzo diffuso", "Nishiki Market"], ["15:00", "Otagi Nenbutsu-ji", "Visita del tempio", "Otagi Nenbutsu-ji"], ["19:30", "Centro", "Cena", "Shijo Kyoto"]], "lunch": {"area": "Nishiki Market", "places": [{"name": "Assaggi a Nishiki", "query": "Nishiki Market Kyoto"}, {"name": "Pranzo diffuso Nishiki", "query": "Nishiki Market lunch Kyoto"}, {"name": "Opzione pranzo 3 · Nishiki Market", "query": "lunch Nishiki Market Kyoto Japan"}, {"name": "Opzione pranzo 4 · Nishiki Market", "query": "lunch Nishiki Market Kyoto Japan"}, {"name": "Opzione pranzo 5 · Nishiki Market", "query": "lunch Nishiki Market Kyoto Japan"}]}, "dinner": {"area": "Centro Kyoto", "places": [{"name": "Kurakura", "query": "Kurakura Kyoto"}, {"name": "Piccolo izakaya centro", "query": "Izakaya central Kyoto"}, {"name": "Opzione cena 3 · Centro Kyoto", "query": "dinner Centro Kyoto Kyoto Japan"}, {"name": "Opzione cena 4 · Centro Kyoto", "query": "dinner Centro Kyoto Kyoto Japan"}, {"name": "Opzione cena 5 · Centro Kyoto", "query": "dinner Centro Kyoto Kyoto Japan"}]}, "onsen": [{"name": "Arashiyama Onsen Kadensho", "query": "Arashiyama Onsen Kadensho Kyoto"}, {"name": "Hanaikada", "query": "Hanaikada Arashiyama Kyoto"}, {"name": "Fufu no Yu", "query": "Fufu no Yu Kyoto"}], "love_hotels": [{"name": "Hotel In The Green", "query": "Hotel In The Green Kyoto"}, {"name": "Hotel Chronos - Adult Only", "query": "Hotel Chronos Kyoto"}, {"name": "Hotel & Spa Lotus", "query": "Hotel & Spa Lotus Kyoto"}]}, {"id": "d24", "date": "24 giugno", "title": "Kobe + Osaka", "city": "Osaka", "base": "Kyoto", "summary": "Kobe beef, castello e neon.", "budget_jpy": [30000, 65000], "hint": "Il momento simbolico è il pranzo a Kobe.", "weather_city": "Osaka, Japan", "timeline": [["09:30", "Kobe", "JR Special Rapid", "Kitanocho Kobe"], ["12:30", "Kobe", "Pranzo Kobe beef", "Sannomiya Kobe"], ["16:00", "Osaka Castle", "Passeggiata", "Osaka Castle"], ["18:30", "Dotonbori", "Cena e street food", "Dotonbori"]], "lunch": {"area": "Kobe", "places": [{"name": "Steakland Kobe", "query": "Steakland Kobe"}, {"name": "Mouriya", "query": "Mouriya Kobe"}, {"name": "Opzione pranzo 3 · Kobe", "query": "lunch Kobe Osaka Japan"}, {"name": "Opzione pranzo 4 · Kobe", "query": "lunch Kobe Osaka Japan"}, {"name": "Opzione pranzo 5 · Kobe", "query": "lunch Kobe Osaka Japan"}]}, "dinner": {"area": "Dotonbori", "places": [{"name": "Akaoni Takoyaki", "query": "Akaoni Dotonbori Osaka"}, {"name": "Ajinoya Honten", "query": "Ajinoya Honten Osaka"}, {"name": "Opzione cena 3 · Dotonbori", "query": "dinner Dotonbori Osaka Japan"}, {"name": "Opzione cena 4 · Dotonbori", "query": "dinner Dotonbori Osaka Japan"}, {"name": "Opzione cena 5 · Dotonbori", "query": "dinner Dotonbori Osaka Japan"}]}, "onsen": [{"name": "Solaniwa Onsen", "query": "Solaniwa Onsen Osaka"}, {"name": "Spa World", "query": "Spa World Osaka"}, {"name": "Naniwa no Yu", "query": "Naniwa no Yu Osaka"}], "love_hotels": [{"name": "Hotel Salle de bain", "query": "Hotel Salle de bain Osaka"}, {"name": "Hotel Lotus Umeda", "query": "Hotel Lotus Umeda Osaka"}, {"name": "HOTEL FIVE plus", "query": "HOTEL FIVE plus Osaka"}]}, {"id": "d25", "date": "25 giugno", "title": "Kyoto → Tokyo + Shibuya Sky", "city": "Tokyo", "base": "Asakusa", "summary": "Rientro morbido e grande tramonto finale su Tokyo.", "budget_jpy": [32000, 55000], "hint": "Shibuya Sky è il cuore della giornata.", "weather_city": "Tokyo, Japan", "timeline": [["10:00", "Tokyo", "Shinkansen", "Tokyo Station"], ["12:30", "Asakusa", "Transfer hotel", "AMANEK Asakusa Sakurabashi"], ["17:30", "Shibuya Sky", "Ingresso al tramonto", "SHIBUYA SKY"], ["19:15", "Shibuya", "Cena", "Shibuya Crossing"]], "lunch": {"area": "Asakusa / Tokyo Station", "places": [{"name": "Lunch veloce Tokyo Station", "query": "Tokyo Station lunch"}, {"name": "Lunch veloce Asakusa", "query": "Lunch Asakusa Tokyo"}, {"name": "Opzione pranzo 3 · Asakusa / Tokyo Station", "query": "lunch Asakusa / Tokyo Station Tokyo Japan"}, {"name": "Opzione pranzo 4 · Asakusa / Tokyo Station", "query": "lunch Asakusa / Tokyo Station Tokyo Japan"}, {"name": "Opzione pranzo 5 · Asakusa / Tokyo Station", "query": "lunch Asakusa / Tokyo Station Tokyo Japan"}]}, "dinner": {"area": "Shibuya", "places": [{"name": "Bistrot a Shibuya", "query": "Bistro Shibuya Tokyo"}, {"name": "Sushi easy Shibuya", "query": "Sushi Shibuya Tokyo"}, {"name": "Opzione cena 3 · Shibuya", "query": "dinner Shibuya Tokyo Japan"}, {"name": "Opzione cena 4 · Shibuya", "query": "dinner Shibuya Tokyo Japan"}, {"name": "Opzione cena 5 · Shibuya", "query": "dinner Shibuya Tokyo Japan"}]}, "onsen": [{"name": "Thermae-Yu Shinjuku", "query": "Thermae-Yu Shinjuku Tokyo"}, {"name": "Asakusa ROX Matsuri-yu", "query": "Asakusa ROX Matsuri-yu Tokyo"}, {"name": "Mikokuyu (sento)", "query": "Mikokuyu Sumida Tokyo"}], "love_hotels": [{"name": "Bali An Resort Shinjuku Forest", "query": "Hotel Bali An Resort Shinjuku Forest Tokyo"}, {"name": "HOTEL & SPA AN Shinjuku Kabukicho", "query": "HOTEL & SPA AN Shinjuku Kabukicho Tokyo"}, {"name": "HOTEL & SPA J-MEX Shinjuku", "query": "HOTEL & SPA J-MEX Shinjuku Tokyo"}]}, {"id": "d26", "date": "26 giugno", "title": "Nikko", "city": "Nikko", "base": "Asakusa", "summary": "Santuari nel bosco e passeggiata a Kanmangafuchi.", "budget_jpy": [22000, 38000], "hint": "Toshogu e Kanmangafuchi bastano.", "weather_city": "Nikko, Japan", "timeline": [["08:30", "Tobu Nikko", "Treno", "Tobu Asakusa Station"], ["11:00", "Nikko Toshogu", "Visita principale", "Nikko Toshogu"], ["14:45", "Kanmangafuchi", "Passeggiata", "Kanmangafuchi Abyss"], ["16:20", "Rientro", "Verso Asakusa", "AMANEK Asakusa Sakurabashi"]], "lunch": {"area": "Nikko", "places": [{"name": "Hippari Dako", "query": "Hippari Dako Nikko"}, {"name": "Yuba lunch Nikko", "query": "Yuba Nikko"}, {"name": "Opzione pranzo 3 · Nikko", "query": "lunch Nikko Nikko Japan"}, {"name": "Opzione pranzo 4 · Nikko", "query": "lunch Nikko Nikko Japan"}, {"name": "Opzione pranzo 5 · Nikko", "query": "lunch Nikko Nikko Japan"}]}, "dinner": {"area": "Asakusa", "places": [{"name": "Cena tranquilla Asakusa", "query": "Restaurant Asakusa Tokyo"}, {"name": "Soba Asakusa", "query": "Soba Asakusa Tokyo"}, {"name": "Opzione cena 3 · Asakusa", "query": "dinner Asakusa Nikko Japan"}, {"name": "Opzione cena 4 · Asakusa", "query": "dinner Asakusa Nikko Japan"}, {"name": "Opzione cena 5 · Asakusa", "query": "dinner Asakusa Nikko Japan"}]}, "onsen": [{"name": "Nikko Station Hotel Classic onsen", "query": "Nikko Station Hotel Classic onsen"}, {"name": "Tattoo friendly private bath Nikko", "query": "private bath Nikko"}, {"name": "Onsen near Tobu Nikko", "query": "onsen Tobu Nikko"}], "love_hotels": [{"name": "Love hotel in zona", "query": "love hotel Nikko Japan"}, {"name": "Adult only hotel in zona", "query": "adult only hotel Nikko Japan"}, {"name": "Short stay hotel in zona", "query": "short stay hotel Nikko Japan"}]}, {"id": "d27", "date": "27 giugno", "title": "Yanaka + ultimo giorno", "city": "Tokyo", "base": "Asakusa", "summary": "Tokyo bassa, ultimi acquisti e cena finale.", "budget_jpy": [20000, 45000], "hint": "Tenete energia per la cena daddio.", "weather_city": "Tokyo, Japan", "timeline": [["10:00", "Yanaka Ginza", "Passeggiata lenta", "Yanaka Ginza"], ["12:00", "Pranzo", "Yanaka / Ueno / Asakusa", "Yanaka Ginza"], ["16:00", "Asakusa", "Ultimi acquisti", "Senso-ji"], ["19:30", "Cena finale", "Teppanyaki o sushi", "Asakusa"]], "lunch": {"area": "Yanaka / Ueno", "places": [{"name": "Lunch informale Yanaka", "query": "Lunch Yanaka Tokyo"}, {"name": "Opzione semplice Ueno", "query": "Lunch Ueno Tokyo"}, {"name": "Opzione pranzo 3 · Yanaka / Ueno", "query": "lunch Yanaka / Ueno Tokyo Japan"}, {"name": "Opzione pranzo 4 · Yanaka / Ueno", "query": "lunch Yanaka / Ueno Tokyo Japan"}, {"name": "Opzione pranzo 5 · Yanaka / Ueno", "query": "lunch Yanaka / Ueno Tokyo Japan"}]}, "dinner": {"area": "Asakusa", "places": [{"name": "Teppanyaki finale", "query": "Teppanyaki Asakusa Tokyo"}, {"name": "Sushi finale", "query": "Sushi Asakusa Tokyo"}, {"name": "Opzione cena 3 · Asakusa", "query": "dinner Asakusa Tokyo Japan"}, {"name": "Opzione cena 4 · Asakusa", "query": "dinner Asakusa Tokyo Japan"}, {"name": "Opzione cena 5 · Asakusa", "query": "dinner Asakusa Tokyo Japan"}]}, "onsen": [{"name": "Asakusa ROX Matsuri-yu", "query": "Asakusa ROX Matsuri-yu Tokyo"}, {"name": "Thermae-Yu Shinjuku", "query": "Thermae-Yu Shinjuku Tokyo"}, {"name": "Daikokuyu (Asakusa area)", "query": "Daikokuyu Tokyo"}], "love_hotels": [{"name": "Bali An Resort Shinjuku Forest", "query": "Hotel Bali An Resort Shinjuku Forest Tokyo"}, {"name": "HOTEL & SPA AN Shinjuku Kabukicho", "query": "HOTEL & SPA AN Shinjuku Kabukicho Tokyo"}, {"name": "HOTEL & SPA J-MEX Shinjuku", "query": "HOTEL & SPA J-MEX Shinjuku Tokyo"}]}, {"id": "d28", "date": "28 giugno", "title": "Rientro", "city": "Tokyo", "base": "Narita / volo", "summary": "Uscita semplice e senza stress.", "budget_jpy": [3000, 8000], "hint": "La prossima tappa è arrivare bene in aeroporto.", "weather_city": "Tokyo, Japan", "timeline": [["07:15", "Check-out", "Partenza con anticipo", "AMANEK Asakusa Sakurabashi"], ["07:30", "Narita", "Transfer aeroporto", "Narita International Airport"], ["09:00", "Narita", "Check-in e controlli", "Narita International Airport"], ["11:10", "Volo", "Partenza", "Narita International Airport"]], "lunch": {"area": "Aeroporto / volo", "places": [{"name": "Snack aeroporto", "query": "Narita Airport restaurants"}, {"name": "Food court Narita", "query": "Narita Airport food court"}, {"name": "Opzione pranzo 3 · Aeroporto / volo", "query": "lunch Aeroporto / volo Tokyo Japan"}, {"name": "Opzione pranzo 4 · Aeroporto / volo", "query": "lunch Aeroporto / volo Tokyo Japan"}, {"name": "Opzione pranzo 5 · Aeroporto / volo", "query": "lunch Aeroporto / volo Tokyo Japan"}]}, "dinner": {"area": "Volo / rientro", "places": [{"name": "Pasto in volo", "query": "Narita International Airport"}, {"name": "Opzione cena 2 · Volo / rientro", "query": "dinner Volo / rientro Tokyo Japan"}, {"name": "Opzione cena 3 · Volo / rientro", "query": "dinner Volo / rientro Tokyo Japan"}, {"name": "Opzione cena 4 · Volo / rientro", "query": "dinner Volo / rientro Tokyo Japan"}, {"name": "Opzione cena 5 · Volo / rientro", "query": "dinner Volo / rientro Tokyo Japan"}]}, "onsen": [{"name": "Asakusa ROX Matsuri-yu", "query": "Asakusa ROX Matsuri-yu Tokyo"}, {"name": "Thermae-Yu Shinjuku", "query": "Thermae-Yu Shinjuku Tokyo"}, {"name": "Daikokuyu (Asakusa area)", "query": "Daikokuyu Tokyo"}], "love_hotels": [{"name": "Bali An Resort Shinjuku Forest", "query": "Hotel Bali An Resort Shinjuku Forest Tokyo"}, {"name": "HOTEL & SPA AN Shinjuku Kabukicho", "query": "HOTEL & SPA AN Shinjuku Kabukicho Tokyo"}, {"name": "HOTEL & SPA J-MEX Shinjuku", "query": "HOTEL & SPA J-MEX Shinjuku Tokyo"}]}];
const HOTELS = [{"city": "Tokyo", "name": "AMANEK Asakusa Sakurabashi", "dates": "1418 giugno · 2528 giugno", "query": "AMANEK Asakusa Sakurabashi Tokyo"}, {"city": "Kanazawa", "name": "Ryokan a Kanazawa", "dates": "1820 giugno", "query": "ryokan Kanazawa station"}, {"city": "Kyoto", "name": "M's Hotel Plus Shijo Omiya", "dates": "2025 giugno", "query": "M's Hotel Plus Shijo Omiya Kyoto"}];
const EURJPY = 182.85;
const LAST_DAY_KEY='jp-trip-last-day-webapp-v27';
const LEGACY_TODO_KEY='jp-trip-todo-stable';
const LEGACY_COSTS_KEY='jp-trip-costs-stable';
const DB_NAME='jp-trip-db-v27';
const STORE='kv';
let dbPromise=null;
function openDB(){
if(dbPromise) return dbPromise;
dbPromise = new Promise((resolve,reject)=>{
const req = indexedDB.open(DB_NAME,1);
req.onupgradeneeded = ()=>{
const db = req.result;
if(!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE);
};
req.onsuccess = ()=> resolve(req.result);
req.onerror = ()=> reject(req.error);
});
return dbPromise;
}
async function idbGet(key, fallback){
try{
const db = await openDB();
return await new Promise((resolve,reject)=>{
const tx = db.transaction(STORE,'readonly');
const req = tx.objectStore(STORE).get(key);
req.onsuccess = ()=> resolve(req.result === undefined ? fallback : req.result);
req.onerror = ()=> reject(req.error);
});
}catch{
return fallback;
}
}
async function idbSet(key, value){
try{
const db = await openDB();
return await new Promise((resolve,reject)=>{
const tx = db.transaction(STORE,'readwrite');
tx.objectStore(STORE).put(value,key);
tx.oncomplete = ()=> resolve(true);
tx.onerror = ()=> reject(tx.error);
});
}catch{
return false;
}
}
function mapsLink(q){ return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(q)}`; }
function jpyToEur(jpy){ return jpy / EURJPY; }
function eurToJpy(eur){ return eur * EURJPY; }
function formatJpy(n){ return '¥' + Number(n||0).toLocaleString('it-IT', {maximumFractionDigits:0}); }
function formatEur(n){ return new Intl.NumberFormat('it-IT', {style:'currency', currency:'EUR'}).format(n||0); }
const todaySelect=document.getElementById('todaySelect'),todayTop=document.getElementById('todayTop'),daysList=document.getElementById('daysList'),cityFilter=document.getElementById('cityFilter');
async function fetchWeather(city) {
try {
const g = await fetch(`https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1&language=it&format=json`);
const gj = await g.json();
if(!gj.results || !gj.results.length) return null;
const r = gj.results[0];
const w = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${r.latitude}&longitude=${r.longitude}&current=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m&timezone=auto`);
const wj = await w.json();
return {name:r.name, current:wj.current};
} catch(e) { return null; }
}
function weatherText(code) {
const map = {0:'Sereno',1:'Poco nuvoloso',2:'Parzialmente nuvoloso',3:'Coperto',45:'Nebbia',48:'Nebbia intensa',51:'Pioviggine leggera',53:'Pioviggine',55:'Pioviggine intensa',61:'Pioggia leggera',63:'Pioggia',65:'Pioggia intensa',71:'Neve leggera',73:'Neve',75:'Neve intensa',80:'Rovesci leggeri',81:'Rovesci',82:'Rovesci forti',95:'Temporale',96:'Temporale con grandine',99:'Temporale forte'};
return map[code] || 'Meteo variabile';
}
function populateSelects(){
todaySelect.innerHTML=DAYS.map(d=>`<option value="${d.id}">${d.date} · ${d.title}</option>`).join('');
const cities=[...new Set(DAYS.map(d=>d.city))].sort();
cityFilter.innerHTML='<option value="">Tutte le città</option>'+cities.map(c=>`<option value="${c}">${c}</option>`).join('');
const last=localStorage.getItem(LAST_DAY_KEY);
if(last&&DAYS.find(d=>d.id===last))todaySelect.value=last;
}
async function renderToday(){
const id=todaySelect.value||DAYS[0].id;
localStorage.setItem(LAST_DAY_KEY,id);
const day=DAYS.find(d=>d.id===id)||DAYS[0];
const stop=day.timeline[0];
const allStops=day.timeline.map(t=>`<div class="trow"><div class="t">${t[0]}</div><div><div class="p">${t[1]}</div><div class="d">${t[2]}</div></div><div><a class="btn ghost" target="_blank" href="${mapsLink(t[3])}">Maps</a></div></div>`).join('');
const lunch=day.lunch.places.slice(0,5).map(p=>`<li><a class="placeLink" target="_blank" href="${mapsLink(p.query)}">${p.name}</a></li>`).join('');
const dinner=day.dinner.places.slice(0,5).map(p=>`<li><a class="placeLink" target="_blank" href="${mapsLink(p.query)}">${p.name}</a></li>`).join('');
const onsen=day.onsen.map(p=>`<li><a class="placeLink" target="_blank" href="${mapsLink(p.query)}">${p.name}</a></li>`).join('');
const love=day.love_hotels.map(p=>`<li><a class="placeLink" target="_blank" href="${mapsLink(p.query)}">${p.name}</a></li>`).join('');
todayTop.innerHTML=`<div class="kpis"><div class="kpi"><div class="label">Dove siete</div><div class="value">${day.city} · ${day.base}</div></div><div class="kpi" id="weatherCard"><div class="label">Meteo</div><div class="value">Caricamento...</div></div></div><div class="nextcard"><div class="time">${stop?stop[0]:'—'}</div><div class="place">${stop?stop[1]:'Nessuna tappa'}</div><div class="desc">${stop?stop[2]:''}</div></div><div class="meal"><h4>Tappe di oggi</h4><div class="timeline">${allStops}</div></div><div class="meal"><h4>Pranzo · zona ${day.lunch.area}</h4><ul>${lunch}</ul></div><div class="meal"><h4>Cena · zona ${day.dinner.area}</h4><ul>${dinner}</ul></div><div class="meal"><h4>Onsen · tattoo friendly / private</h4><ul>${onsen}</ul></div><div class="meal"><h4>Love hotel in zona</h4><ul>${love}</ul></div>`;
const weather=await fetchWeather(day.weather_city);
const wc=document.getElementById('weatherCard');
if(wc){
if(weather&&weather.current){
wc.innerHTML=`<div class="label">Meteo · ${weather.name}</div><div class="weatherBox"><div><div class="value">${weatherText(weather.current.weather_code)}</div><div class="small">Umidità ${weather.current.relative_humidity_2m}% · Vento ${weather.current.wind_speed_10m} km/h</div></div><div class="weatherTemp">${Math.round(weather.current.temperature_2m)}°</div></div>`;
} else {
wc.innerHTML='<div class="label">Meteo</div><div class="value">Non disponibile</div>';
}
}
}
function renderDays(){
const q=document.getElementById('searchInput').value.trim().toLowerCase();
const city=cityFilter.value;
const items=DAYS.filter(d=>(!q||JSON.stringify(d).toLowerCase().includes(q))&&(!city||d.city===city));
daysList.innerHTML=items.map(d=>`<div class="daylist-item"><h3>${d.date} · ${d.title}</h3><div class="muted">${d.city} · ${d.summary}</div><div class="actions" style="margin-top:10px"><button class="btn ghost open-day" data-id="${d.id}">Apri in Oggi</button></div></div>`).join('');
document.querySelectorAll('.open-day').forEach(b=>b.onclick=()=>{todaySelect.value=b.dataset.id;renderToday();location.hash='#oggi';});
}
function renderHotels(){
const host=document.getElementById('hotelList');
host.innerHTML=HOTELS.map(h=>`<div class="daylist-item"><h3>${h.name}</h3><div class="muted">${h.city} · ${h.dates}</div><div class="actions" style="margin-top:10px"><a class="btn ghost" target="_blank" href="${mapsLink(h.query)}">Maps</a></div></div>`).join('');
}
async function migrateLegacyData(){
const legacyTodo = localStorage.getItem(LEGACY_TODO_KEY);
const legacyCosts = localStorage.getItem(LEGACY_COSTS_KEY);
const existingTodo = await idbGet('todoData', null);
const existingCosts = await idbGet('costData', null);
if(legacyTodo && existingTodo === null){
try{ await idbSet('todoData', JSON.parse(legacyTodo)); }catch{}
}
if(legacyCosts && existingCosts === null){
try{ await idbSet('costData', JSON.parse(legacyCosts)); }catch{}
}
}
async function renderTodo(){
const defaultTodo = ['Passaporti controllati','Assicurazione viaggio attiva','Prenotazioni hotel verificate','Biglietti aerei salvati','eSIM / SIM dati attivata','Carte e contanti pronti','Power bank carico','Adattatore prese in valigia','Prenotazioni teamLab / Shibuya Sky','Bagaglio e documenti finali'];
let state = await idbGet('todoData', null);
if(state === null){
state = defaultTodo.map(t=>({text:t,done:false}));
await idbSet('todoData', state);
}
const host=document.getElementById('todoList');
host.innerHTML=state.map((item,i)=>`<label class="todo-item"><input type="checkbox" data-i="${i}" ${item.done?'checked':''}><div>${item.text}</div></label>`).join('');
host.querySelectorAll('input[type=checkbox]').forEach(cb=>cb.onchange=async ()=>{
const s = await idbGet('todoData', []);
s[Number(cb.dataset.i)].done = cb.checked;
await idbSet('todoData', s);
});
}
async function renderCosts(){
const costs = await idbGet('costData', []);
const host=document.getElementById('costList');
host.innerHTML=costs.length?costs.map((c,i)=>`<div class="cost-row"><div style="flex:1;min-width:0"><div class="p">${c.desc}</div><div class="small">${formatJpy(c.jpy)} · ${formatEur(c.eur)}</div></div><button class="btn ghost del-cost" data-i="${i}">Elimina</button></div>`).join(''):'<div class="small" style="margin-top:12px">Nessuna spesa inserita.</div>';
const totalJpy=costs.reduce((a,c)=>a+Number(c.jpy||0),0);
const totalEur=costs.reduce((a,c)=>a+Number(c.eur||0),0);
document.getElementById('totalJpy').textContent=formatJpy(totalJpy);
document.getElementById('totalEur').textContent=formatEur(totalEur);
host.querySelectorAll('.del-cost').forEach(b=>b.onclick=async ()=>{
const s = await idbGet('costData', []);
s.splice(Number(b.dataset.i),1);
await idbSet('costData', s);
renderCosts();
});
}
todaySelect.onchange=renderToday;
document.getElementById('prevDay').onclick=()=>{const idx=DAYS.findIndex(d=>d.id===todaySelect.value);if(idx>0)todaySelect.value=DAYS[idx-1].id;renderToday();};
document.getElementById('nextDay').onclick=()=>{const idx=DAYS.findIndex(d=>d.id===todaySelect.value);if(idx<DAYS.length-1)todaySelect.value=DAYS[idx+1].id;renderToday();};
document.getElementById('searchInput').oninput=renderDays;cityFilter.onchange=renderDays;
document.getElementById('addCostBtn').onclick=async ()=>{
const desc=document.getElementById('costDesc').value.trim();
const jpyRaw=document.getElementById('costJpy').value;
const eurRaw=document.getElementById('costEur').value;
const jpyVal=Number(jpyRaw);
const eurVal=Number(eurRaw);
if(!desc) return;
let jpy=0, eur=0;
if(jpyVal>0){ jpy=jpyVal; eur=jpyToEur(jpyVal); }
else if(eurVal>0){ eur=eurVal; jpy=eurToJpy(eurVal); }
else { return; }
const s=await idbGet('costData',[]);
s.unshift({desc,jpy,eur});
await idbSet('costData',s);
document.getElementById('costDesc').value='';
document.getElementById('costJpy').value='';
document.getElementById('costEur').value='';
renderCosts();
};
document.getElementById('clearCostsBtn').onclick=async ()=>{await idbSet('costData',[]);renderCosts();};
(async function init(){
populateSelects();
await migrateLegacyData();
renderToday();
renderDays();
renderHotels();
await renderTodo();
await renderCosts();
})();